From 08b5a30dc00cc9f2a4f36ac31eae4308cbc392db Mon Sep 17 00:00:00 2001 From: Hyunil Park Date: Wed, 11 Feb 2015 13:57:24 +0900 Subject: [PATCH] Update Initialization code from Tizen 2.4 blocked plugins : xvimagesrc, wfdrtspsrc, fimcconvert, evaspixmapsink Change-Id: Icd407087cdac9dd4c06731180d589375e3d7adb6 Signed-off-by: Hyunil Park --- AUTHORS | 5 + COPYING | 504 ++ INSTALL | 236 + Makefile.am | 90 + PLUGINS | 15 + README | 12 + audioeq/Makefile.am | 1 + audioeq/src/Makefile.am | 28 + audioeq/src/gstaudioeq.c | 1292 ++++++ audioeq/src/gstaudioeq.h | 127 + audiotp/Makefile.am | 1 + audiotp/src/Makefile.am | 26 + audiotp/src/gstaudiotp.c | 559 +++ audiotp/src/gstaudiotp.h | 69 + autogen.sh | 12 + autoregen.sh | 2 + common/ChangeLog | 1343 ++++++ common/Makefile.am | 16 + common/c-to-xml.py | 34 + common/check-exports | 71 + common/check.mak | 149 + common/coverage/coverage-report-entry.pl | 70 + common/coverage/coverage-report.pl | 125 + common/coverage/coverage-report.xsl | 235 + common/coverage/lcov.mak | 42 + common/gettext.patch | 23 + common/glib-gen.mak | 44 + common/gst-autogen.sh | 294 ++ common/gst-xmlinspect.py | 168 + common/gst.supp | 1988 ++++++++ common/gstdoc-scangobj | 1607 +++++++ common/gtk-doc-plugins.mak | 397 ++ common/gtk-doc.mak | 267 ++ common/m4/Makefile.am | 29 + common/m4/README | 3 + common/m4/as-ac-expand.m4 | 43 + common/m4/as-auto-alt.m4 | 50 + common/m4/as-compiler-flag.m4 | 64 + common/m4/as-compiler.m4 | 44 + common/m4/as-docbook.m4 | 66 + common/m4/as-gcc-inline-assembly.m4 | 52 + common/m4/as-libtool-tags.m4 | 83 + common/m4/as-libtool.m4 | 45 + common/m4/as-python.m4 | 152 + common/m4/as-scrub-include.m4 | 36 + common/m4/as-version.m4 | 71 + common/m4/ax_create_stdint_h.m4 | 734 +++ common/m4/check.m4 | 181 + common/m4/gettext.m4 | 587 +++ common/m4/glib-gettext.m4 | 380 ++ common/m4/gst-arch.m4 | 123 + common/m4/gst-args.m4 | 302 ++ common/m4/gst-check.m4 | 138 + common/m4/gst-debuginfo.m4 | 46 + common/m4/gst-default.m4 | 45 + common/m4/gst-doc.m4 | 148 + common/m4/gst-error.m4 | 145 + common/m4/gst-feature.m4 | 286 ++ common/m4/gst-function.m4 | 63 + common/m4/gst-gettext.m4 | 21 + common/m4/gst-glib2.m4 | 25 + common/m4/gst-libxml2.m4 | 46 + common/m4/gst-parser.m4 | 63 + common/m4/gst-plugin-docs.m4 | 47 + common/m4/gst-plugindir.m4 | 17 + common/m4/gst-valgrind.m4 | 35 + common/m4/gst-x11.m4 | 70 + common/m4/gst.m4 | 10 + common/m4/gtk-doc.m4 | 56 + common/m4/iconv.m4 | 103 + common/m4/isc-posix.m4 | 26 + common/m4/lib-ld.m4 | 97 + common/m4/lib-link.m4 | 554 +++ common/m4/lib-prefix.m4 | 148 + common/m4/libtool.m4 | 7377 ++++++++++++++++++++++++++++++ common/m4/ltoptions.m4 | 368 ++ common/m4/ltsugar.m4 | 123 + common/m4/ltversion.m4 | 23 + common/m4/lt~obsolete.m4 | 92 + common/m4/pkg.m4 | 135 + common/m4/progtest.m4 | 59 + common/mangle-tmpl.py | 155 + common/plugins.xsl | 200 + common/po.mak | 4 + common/release.mak | 25 + common/scangobj-merge.py | 226 + common/upload.mak | 33 + common/win32.mak | 54 + configure.ac | 460 ++ drmsrc/Makefile.am | 1 + drmsrc/src/Makefile.am | 27 + drmsrc/src/gstdrmsrc.c | 604 +++ drmsrc/src/gstdrmsrc.h | 82 + encodebin/Makefile.am | 1 + encodebin/src/Makefile.am | 30 + encodebin/src/gstencodebin.c | 3003 ++++++++++++ encodebin/src/gstencodebin.h | 159 + evasimagesink/Makefile.am | 1 + evasimagesink/src/Makefile.am | 26 + evasimagesink/src/gstevasimagesink.c | 2019 ++++++++ evasimagesink/src/gstevasimagesink.h | 170 + evaspixmapsink/Makefile.am | 14 + evaspixmapsink/evaspixmapsink.c | 3755 +++++++++++++++ evaspixmapsink/evaspixmapsink.h | 388 ++ evaspixmapsink/xv_types.h | 41 + fimcconvert/Makefile.am | 15 + fimcconvert/src/Makefile.am | 27 + fimcconvert/src/fimc_drm_api.c | 412 ++ fimcconvert/src/fimc_drm_api.h | 63 + fimcconvert/src/gstfimcconvert.c | 2717 +++++++++++ fimcconvert/src/gstfimcconvert.h | 380 ++ gst-autogen.sh | 308 ++ gst-plugins-tizen1.0.manifest | 5 + m4/Makefile.am | 1 + m4/as-compiler-flag.m4 | 25 + m4/as-version.m4 | 66 + packaging/gst-plugins-tizen.spec | 56 + pdpushsrc/Makefile.am | 1 + pdpushsrc/src/Makefile.am | 26 + pdpushsrc/src/gstpdpushsrc.c | 820 ++++ pdpushsrc/src/gstpdpushsrc.h | 73 + toggle/Makefile.am | 1 + toggle/src/Makefile.am | 30 + toggle/src/gsttoggle.c | 210 + toggle/src/gsttoggle.h | 61 + wfdrtspsrc/Makefile.am | 1 + wfdrtspsrc/src/Makefile.am | 35 + wfdrtspsrc/src/gstwfdrtprequester.c | 1195 +++++ wfdrtspsrc/src/gstwfdrtprequester.h | 102 + wfdrtspsrc/src/gstwfdrtspext.c | 273 ++ wfdrtspsrc/src/gstwfdrtspext.h | 88 + wfdrtspsrc/src/gstwfdrtspsrc.c | 4645 +++++++++++++++++++ wfdrtspsrc/src/gstwfdrtspsrc.h | 187 + wfdrtspsrc/src/wfdrtspmanager.c | 1184 +++++ wfdrtspsrc/src/wfdrtspmanager.h | 159 + xvimagesrc/Makefile.am | 1 + xvimagesrc/src/Makefile.am | 26 + xvimagesrc/src/gstxvimagesrc.c | 1875 ++++++++ xvimagesrc/src/gstxvimagesrc.h | 140 + xvimagesrc/src/xv_types.h | 169 + 140 files changed, 50118 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 PLUGINS create mode 100644 README create mode 100755 audioeq/Makefile.am create mode 100755 audioeq/src/Makefile.am create mode 100644 audioeq/src/gstaudioeq.c create mode 100644 audioeq/src/gstaudioeq.h create mode 100755 audiotp/Makefile.am create mode 100755 audiotp/src/Makefile.am create mode 100644 audiotp/src/gstaudiotp.c create mode 100755 audiotp/src/gstaudiotp.h create mode 100755 autogen.sh create mode 100755 autoregen.sh create mode 100755 common/ChangeLog create mode 100644 common/Makefile.am create mode 100755 common/c-to-xml.py create mode 100755 common/check-exports create mode 100755 common/check.mak create mode 100755 common/coverage/coverage-report-entry.pl create mode 100755 common/coverage/coverage-report.pl create mode 100755 common/coverage/coverage-report.xsl create mode 100755 common/coverage/lcov.mak create mode 100755 common/gettext.patch create mode 100755 common/glib-gen.mak create mode 100755 common/gst-autogen.sh create mode 100755 common/gst-xmlinspect.py create mode 100755 common/gst.supp create mode 100755 common/gstdoc-scangobj create mode 100755 common/gtk-doc-plugins.mak create mode 100755 common/gtk-doc.mak create mode 100644 common/m4/Makefile.am create mode 100755 common/m4/README create mode 100755 common/m4/as-ac-expand.m4 create mode 100755 common/m4/as-auto-alt.m4 create mode 100755 common/m4/as-compiler-flag.m4 create mode 100755 common/m4/as-compiler.m4 create mode 100755 common/m4/as-docbook.m4 create mode 100755 common/m4/as-gcc-inline-assembly.m4 create mode 100755 common/m4/as-libtool-tags.m4 create mode 100755 common/m4/as-libtool.m4 create mode 100755 common/m4/as-python.m4 create mode 100755 common/m4/as-scrub-include.m4 create mode 100755 common/m4/as-version.m4 create mode 100755 common/m4/ax_create_stdint_h.m4 create mode 100755 common/m4/check.m4 create mode 100755 common/m4/gettext.m4 create mode 100755 common/m4/glib-gettext.m4 create mode 100755 common/m4/gst-arch.m4 create mode 100755 common/m4/gst-args.m4 create mode 100755 common/m4/gst-check.m4 create mode 100755 common/m4/gst-debuginfo.m4 create mode 100755 common/m4/gst-default.m4 create mode 100755 common/m4/gst-doc.m4 create mode 100755 common/m4/gst-error.m4 create mode 100755 common/m4/gst-feature.m4 create mode 100755 common/m4/gst-function.m4 create mode 100755 common/m4/gst-gettext.m4 create mode 100755 common/m4/gst-glib2.m4 create mode 100755 common/m4/gst-libxml2.m4 create mode 100755 common/m4/gst-parser.m4 create mode 100755 common/m4/gst-plugin-docs.m4 create mode 100755 common/m4/gst-plugindir.m4 create mode 100755 common/m4/gst-valgrind.m4 create mode 100644 common/m4/gst-x11.m4 create mode 100755 common/m4/gst.m4 create mode 100755 common/m4/gtk-doc.m4 create mode 100755 common/m4/iconv.m4 create mode 100755 common/m4/isc-posix.m4 create mode 100755 common/m4/lib-ld.m4 create mode 100755 common/m4/lib-link.m4 create mode 100755 common/m4/lib-prefix.m4 create mode 100644 common/m4/libtool.m4 create mode 100644 common/m4/ltoptions.m4 create mode 100644 common/m4/ltsugar.m4 create mode 100644 common/m4/ltversion.m4 create mode 100644 common/m4/lt~obsolete.m4 create mode 100755 common/m4/pkg.m4 create mode 100755 common/m4/progtest.m4 create mode 100755 common/mangle-tmpl.py create mode 100755 common/plugins.xsl create mode 100755 common/po.mak create mode 100755 common/release.mak create mode 100755 common/scangobj-merge.py create mode 100755 common/upload.mak create mode 100755 common/win32.mak create mode 100644 configure.ac create mode 100755 drmsrc/Makefile.am create mode 100755 drmsrc/src/Makefile.am create mode 100755 drmsrc/src/gstdrmsrc.c create mode 100755 drmsrc/src/gstdrmsrc.h create mode 100644 encodebin/Makefile.am create mode 100644 encodebin/src/Makefile.am create mode 100644 encodebin/src/gstencodebin.c create mode 100644 encodebin/src/gstencodebin.h create mode 100644 evasimagesink/Makefile.am create mode 100644 evasimagesink/src/Makefile.am create mode 100755 evasimagesink/src/gstevasimagesink.c create mode 100644 evasimagesink/src/gstevasimagesink.h create mode 100644 evaspixmapsink/Makefile.am create mode 100755 evaspixmapsink/evaspixmapsink.c create mode 100755 evaspixmapsink/evaspixmapsink.h create mode 100644 evaspixmapsink/xv_types.h create mode 100755 fimcconvert/Makefile.am create mode 100755 fimcconvert/src/Makefile.am create mode 100755 fimcconvert/src/fimc_drm_api.c create mode 100755 fimcconvert/src/fimc_drm_api.h create mode 100755 fimcconvert/src/gstfimcconvert.c create mode 100755 fimcconvert/src/gstfimcconvert.h create mode 100755 gst-autogen.sh create mode 100644 gst-plugins-tizen1.0.manifest create mode 100644 m4/Makefile.am create mode 100755 m4/as-compiler-flag.m4 create mode 100755 m4/as-version.m4 create mode 100644 packaging/gst-plugins-tizen.spec create mode 100755 pdpushsrc/Makefile.am create mode 100755 pdpushsrc/src/Makefile.am create mode 100644 pdpushsrc/src/gstpdpushsrc.c create mode 100755 pdpushsrc/src/gstpdpushsrc.h create mode 100755 toggle/Makefile.am create mode 100755 toggle/src/Makefile.am create mode 100755 toggle/src/gsttoggle.c create mode 100755 toggle/src/gsttoggle.h create mode 100755 wfdrtspsrc/Makefile.am create mode 100755 wfdrtspsrc/src/Makefile.am create mode 100755 wfdrtspsrc/src/gstwfdrtprequester.c create mode 100755 wfdrtspsrc/src/gstwfdrtprequester.h create mode 100755 wfdrtspsrc/src/gstwfdrtspext.c create mode 100755 wfdrtspsrc/src/gstwfdrtspext.h create mode 100755 wfdrtspsrc/src/gstwfdrtspsrc.c create mode 100755 wfdrtspsrc/src/gstwfdrtspsrc.h create mode 100755 wfdrtspsrc/src/wfdrtspmanager.c create mode 100755 wfdrtspsrc/src/wfdrtspmanager.h create mode 100644 xvimagesrc/Makefile.am create mode 100644 xvimagesrc/src/Makefile.am create mode 100644 xvimagesrc/src/gstxvimagesrc.c create mode 100644 xvimagesrc/src/gstxvimagesrc.h create mode 100644 xvimagesrc/src/xv_types.h diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..96cbfc8 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,5 @@ +JongHyuk Choi +Seungbae Shin +Younghwan Ahn +Jeongmo Yang +Sangchul Lee 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. + + + Copyright (C) + + 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. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..23e5f25 --- /dev/null +++ b/INSTALL @@ -0,0 +1,236 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free +Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). Here is a another example: + + /bin/bash ./configure CONFIG_SHELL=/bin/bash + +Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent +configuration-related scripts to be executed by `/bin/bash'. + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..8849fba --- /dev/null +++ b/Makefile.am @@ -0,0 +1,90 @@ + +ACLOCAL_AMFLAGS = -I common/m4 + +aclocaldir = $(datadir)/aclocal + +SUBDIRS = common + +if GST_EXT_USE_EXT_ENCODEBIN +SUBDIRS += encodebin +endif + +if GST_EXT_USE_EXT_EVASIMAGESINK +SUBDIRS += evasimagesink +endif + +#if GST_EXT_USE_EXT_EVASPIXMAPSINK +#SUBDIRS += evaspixmapsink +#endif + +#if GST_EXT_USE_EXT_XVIMAGESRC +#SUBDIRS += xvimagesrc +#endif + +if GST_EXT_USE_EXT_DRMSRC +SUBDIRS += drmsrc +endif + +if GST_EXT_USE_EXT_TOGGLE +SUBDIRS += toggle +endif + +if GST_EXT_USE_EXT_PD_PUSHSRC +SUBDIRS += pdpushsrc +endif + +if GST_EXT_USE_EXT_AUDIOTP +SUBDIRS += audiotp +endif + +if GST_EXT_USE_EXT_AUDIOEQ +SUBDIRS += audioeq +endif + +#if GST_EXT_USE_EXT_FIMCCONVERT +#SUBDIRS += fimcconvert +#endif + +#if GST_EXT_USE_EXT_WFDRTSPSRC +#SUBDIRS += wfdrtspsrc +#endif + +DIST_SUBDIRS = common + +if GST_EXT_USE_EXT_ENCODEBIN +DIST_SUBDIRS += encodebin +endif + +if GST_EXT_USE_EXT_EVASIMAGESINK +DIST_SUBDIRS += evasimagesink +endif + +if GST_EXT_USE_EXT_XVIMAGESRC +DIST_SUBDIRS += xvimagesrc +endif + +if GST_EXT_USE_EXT_DRMSRC +DIST_SUBDIRS += drmsrc +endif + +if GST_EXT_USE_EXT_TOGGLE +DIST_SUBDIRS += toggle +endif + +if GST_EXT_USE_EXT_FIMCCONVERT +DIST_SUBDIRS += fimcconvert +endif + + +#if GST_EXT_USE_EXT_WFDRTSPSRC +#DIST_SUBDIRS += wfdrtspsrc +#endif + +EXTRA_DIST = \ + gstreamer.spec gstreamer.spec.in \ + configure.ac autogen.sh depcomp \ + MAINTAINERS ABOUT-NLS RELEASE gstreamer.doap \ + $(win32) + +check: check-exports + diff --git a/PLUGINS b/PLUGINS new file mode 100644 index 0000000..a737f3a --- /dev/null +++ b/PLUGINS @@ -0,0 +1,15 @@ +# This file is descriptions of the plugins which are included in gstreamer0.10-plugins-ext. +# If any plugin is added to the gstreamer0.10-plugins-ext, that shoud be described in this file. +# +# + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +PLUGIN Registered Elements Description +------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +avsysaudiosrc avsysaudiosrc AV system audio source plugin +avsyssink avsysaudiosink, avsysmemsink AV system audio sink plugin +drmsrc drmsrc Plugin to read data from standad/DRM file +encodebin encodebin Extension encoder bin plugin +evasimagesink evasimagesink Evas video sink plugin +toggle toggle Base transform plugin +------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/README b/README new file mode 100644 index 0000000..9681276 --- /dev/null +++ b/README @@ -0,0 +1,12 @@ +gst-plugin is a template for writing your own GStreamer plug-in. + +The code is deliberately kept simple so that you quickly understand the basics +of how to set up autotools and your source tree. + +This template demonstrates : +- what to do in autogen.sh +- how to setup configure.ac (your package name and version, GStreamer flags) +- how to setup your source dir +- what to put in Makefile.am + +More features might get added to this template later on. diff --git a/audioeq/Makefile.am b/audioeq/Makefile.am new file mode 100755 index 0000000..308a09c --- /dev/null +++ b/audioeq/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/audioeq/src/Makefile.am b/audioeq/src/Makefile.am new file mode 100755 index 0000000..c077e2c --- /dev/null +++ b/audioeq/src/Makefile.am @@ -0,0 +1,28 @@ +# plugindir is set in configure + +############################################################################## +# change libgstplugin.la to something more suitable, e.g. libmysomething.la # +############################################################################## +plugin_LTLIBRARIES = libgstaudioeq.la + +############################################################################## +# for the next set of variables, rename the prefix if you renamed the .la, # +# e.g. libgstplugin_la_SOURCES => libmysomething_la_SOURCES # +# libgstplugin_la_CFLAGS => libmysomething_la_CFLAGS # +# libgstplugin_la_LIBADD => libmysomething_la_LIBADD # +# libgstplugin_la_LDFLAGS => libmysomething_la_LDFLAGS # +############################################################################## + +# sources used to compile this plug-in +libgstaudioeq_la_SOURCES = gstaudioeq.c + +# flags used to compile this plugin +# add other _CFLAGS and _LIBS as needed +libgstaudioeq_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CONTROLLER_CFLAGS) +libgstaudioeq_la_LIBADD = $(GST_LIBS) $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) $(GST_BASE_LIBS) $(GST_CONTROLLER_LIBS) $(GST_LIBS) $(LIBM) -lgstbase-1.0 -lglib-2.0 -lgstcontroller-1.0 +libgstaudioeq_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +libgstequalizer_la_LIBTOOLFLAGS = --tag=disable-static + +# headers we need but don't want installed +noinst_HEADERS = gstaudioeq.h diff --git a/audioeq/src/gstaudioeq.c b/audioeq/src/gstaudioeq.c new file mode 100644 index 0000000..3fe2751 --- /dev/null +++ b/audioeq/src/gstaudioeq.c @@ -0,0 +1,1292 @@ +/* + * audioeq + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Aditi Narula + * + * 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 +#endif + +#include "gstaudioeq.h" +#include +#include + +GST_DEBUG_CATEGORY_STATIC (gst_audioeq_debug); +#define GST_CAT_DEFAULT gst_audioeq_debug + +#define AUDIOEQ_ENABLE_DUMP +#define AUDIOEQ_REDUCE_MEMCPY + +/* Filter signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_FILTER_ACTION, + PROP_CUSTOM_EQ, + PROP_CUSTOM_EQ_NUM, + PROP_CUSTOM_EQ_FREQ, + PROP_CUSTOM_EQ_WIDTH, +}; + +enum FilterActionType +{ + FILTER_NONE, + FILTER_PRESET, + FILTER_ADVANCED_SETTING +}; + +enum SampleRate +{ + SAMPLERATE_48000Hz, + SAMPLERATE_44100Hz, + SAMPLERATE_32000Hz, + SAMPLERATE_24000Hz, + SAMPLERATE_22050Hz, + SAMPLERATE_16000Hz, + SAMPLERATE_12000Hz, + SAMPLERATE_11025Hz, + SAMPLERATE_8000Hz, + + SAMPLERATE_NUM +}; + +#define DEFAULT_SAMPLE_SIZE 2 +#define DEFAULT_VOLUME 15 +#define DEFAULT_GAIN 1 +#define DEFAULT_SAMPLE_RATE SAMPLERATE_44100Hz +#define DEAFULT_CHANNELS 2 +#define DEFAULT_FILTER_ACTION FILTER_NONE +#define DEFAULT_CUSTOM_EQ_NUM 7 + +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) ", " + "channels = (int) [1,2]" + ) + ); + +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) ", " + "channels = (int) [1,2]" + ) + ); + +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, + GstAudioRingBufferSpec * fmt); + +G_DEFINE_TYPE_WITH_CODE(Gstaudioeq, gst_audioeq, GST_TYPE_BASE_TRANSFORM, + G_IMPLEMENT_INTERFACE(GST_TYPE_CHILD_PROXY, gst_iir_equalizer_child_proxy_interface_init)); + +static void gst_audioeq_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); +static void gst_audioeq_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); +#ifdef AUDIOEQ_REDUCE_MEMCPY +static GstFlowReturn gst_audioeq_transform_ip (GstBaseTransform * base, GstBuffer * buf); +#else +static GstFlowReturn gst_audioeq_transform (GstBaseTransform * base, GstBuffer * inbuf, GstBuffer * outbuf); +#endif +static gboolean gst_audioeq_set_caps (GstBaseTransform * base, GstCaps * incaps, GstCaps * outcaps); + +static GstStateChangeReturn +gst_audioeq_change_state (GstElement * element, GstStateChange transition) +{ + GST_DEBUG ("gst_audioeq_change_state"); + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + Gstaudioeq *audioeq = GST_AUDIOEQ (element); + + switch (transition) { + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + audioeq->need_update_filter = TRUE; + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (gst_audioeq_parent_class)->change_state (element, transition); + + if (ret == GST_STATE_CHANGE_FAILURE) + return ret; + + switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; + default: + break; + } + + return ret; +} + +static void +gst_audioeq_base_init (gpointer gclass) +{ + + GST_DEBUG ("gst_audioeq_base_init"); +} + +static void +gst_audioeq_class_init (GstaudioeqClass * klass) +{ + GST_DEBUG ("gst_audioeq_class_init"); + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseTransformClass *basetransform_class; + + gobject_class = G_OBJECT_CLASS (klass); + gstelement_class = GST_ELEMENT_CLASS (klass); + basetransform_class = GST_BASE_TRANSFORM_CLASS(klass); + + gobject_class->set_property = GST_DEBUG_FUNCPTR(gst_audioeq_set_property); + gobject_class->get_property = GST_DEBUG_FUNCPTR(gst_audioeq_get_property); + + gst_element_class_add_pad_template(gstelement_class, + gst_static_pad_template_get (&srctemplate)); + gst_element_class_add_pad_template(gstelement_class, + gst_static_pad_template_get (&sinktemplate)); + + gst_element_class_set_static_metadata(gstelement_class, + "Audio Equalizer", + "Filter/Effect/Audio", + "Set equalisation effect on audio/raw streams", + "Samsung Electronics "); + gstelement_class->change_state = GST_DEBUG_FUNCPTR(gst_audioeq_change_state); + + g_object_class_install_property(gobject_class, PROP_FILTER_ACTION, + g_param_spec_uint("filter-action", "filter action", "(0)none (1)preset (2)advanced setting", + 0, 2, DEFAULT_FILTER_ACTION, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_CUSTOM_EQ, + g_param_spec_pointer("custom-eq", "custom eq", + "pointer for 9 bands of EQ array", G_PARAM_READWRITE)); + + g_object_class_install_property(gobject_class, PROP_CUSTOM_EQ_NUM, + g_param_spec_uint("custom-eq-num", "custom eq num", "number of custom EQ bands", + 0, 9, DEFAULT_CUSTOM_EQ_NUM, G_PARAM_READABLE)); + + g_object_class_install_property(gobject_class, PROP_CUSTOM_EQ_FREQ, + g_param_spec_pointer("custom-eq-freq", "custom eq freq", "pointer for EQ bands central frequency(Hz) array", + G_PARAM_READABLE)); + + g_object_class_install_property(gobject_class, PROP_CUSTOM_EQ_WIDTH, + g_param_spec_pointer("custom-eq-width", "custom eq width", "pointer for EQ bands width(Hz) array", + G_PARAM_READABLE)); + + gobject_class->finalize = GST_DEBUG_FUNCPTR(gst_iir_equalizer_finalize); + +/* It is possible to reduce memcpy by setting output same as input of AudioEq_InOutConfig */ +#ifdef AUDIOEQ_REDUCE_MEMCPY + basetransform_class->transform_ip = GST_DEBUG_FUNCPTR(gst_audioeq_transform_ip); +#endif + basetransform_class->set_caps = GST_DEBUG_FUNCPTR(gst_audioeq_set_caps); +} + +static void +gst_audioeq_init (Gstaudioeq * audioeq) +{ + GST_DEBUG ("gst_audioeq_init"); + audioeq->samplerate = DEFAULT_SAMPLE_RATE; + audioeq->channels = DEAFULT_CHANNELS; + + audioeq->filter_action = DEFAULT_FILTER_ACTION; + memset(audioeq->custom_eq, 0x00, sizeof(gint) * CUSTOM_EQ_BAND_MAX); + audioeq->need_update_filter = TRUE; + audioeq->equ.bands_lock = g_mutex_new (); + audioeq->equ.need_new_coefficients = TRUE; + gst_iir_equalizer_compute_frequencies (audioeq, DEFAULT_CUSTOM_EQ_NUM); +} +/* equalizer implementation */ + +static void +gst_iir_equalizer_finalize (GObject * object) +{ + GST_DEBUG ("gst_iir_equalizer_finalize"); + Gstaudioeq *audioeq = GST_AUDIOEQ(object); + GstIirEqualizer *equ = &audioeq->equ; + 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_free (equ->bands_lock); + + G_OBJECT_CLASS (gst_audioeq_parent_class)->finalize (object); +} + +#define BANDS_LOCK(equ) g_mutex_lock(equ->bands_lock) +#define BANDS_UNLOCK(equ) g_mutex_unlock(equ->bands_lock) + +/* 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) +{ + GST_DEBUG ("gst_iir_equalizer_band_type_get_type"); + 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) +{ + GST_DEBUG ("gst_iir_equalizer_band_set_property"); + GstIirEqualizerBand *band = GST_IIR_EQUALIZER_BAND (object); + Gstaudioeq *audioeq = GST_AUDIOEQ (gst_object_get_parent (GST_OBJECT (band))); + GstIirEqualizer *equ = &audioeq->equ; + + 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; + 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 (audioeq); +} + +static void +gst_iir_equalizer_band_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GST_DEBUG ("gst_iir_equalizer_band_get_property"); + 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) +{ + GST_DEBUG ("gst_iir_equalizer_band_class_init"); + 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 -12.0 dB to +12.0 dB", + -12.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) +{ + GST_DEBUG ("gst_iir_equalizer_band_init"); + 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) +{ + GST_DEBUG ("gst_iir_equalizer_band_get_type"); + 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) +{ + GST_DEBUG ("gst_iir_equalizer_child_proxy_get_child_by_index"); + Gstaudioeq *audioeq = GST_AUDIOEQ(child_proxy); + GstIirEqualizer *equ = &audioeq->equ; + 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 = gst_object_ref (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) +{ + GST_DEBUG ("gst_iir_equalizer_child_proxy_get_children_count"); + Gstaudioeq *audioeq = GST_AUDIOEQ(child_proxy); + GstIirEqualizer *equ = &audioeq->equ; + + 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; +} +static void +gst_iir_equalizer_class_init (GstIirEqualizerClass * klass) +{ + GST_DEBUG ("gst_iir_equalizer_class_init"); +} + +static void +gst_iir_equalizer_init (GstIirEqualizer * eq, GstIirEqualizerClass * g_class) +{ + GST_DEBUG ("gst_iir_equalizer_init"); + eq->bands_lock = g_mutex_new (); + eq->need_new_coefficients = TRUE; +} + +GType +gst_iir_equalizer_get_type (void) +{ + GST_DEBUG ("gst_iir_equalizer_get_type"); + static GType type = 0; + + if (G_UNLIKELY (!type)) { + const GTypeInfo type_info = { + sizeof (GstIirEqualizerClass), + NULL, + NULL, + (GClassInitFunc) gst_iir_equalizer_class_init, + NULL, + NULL, + sizeof (GstIirEqualizer), + 0, + (GInstanceInitFunc) gst_iir_equalizer_init, + }; + type = + g_type_register_static (GST_TYPE_OBJECT, "GstIirEqualizer", + &type_info, 0); + } + return (type); +} +/* 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) +{ + GST_DEBUG ("arg_to_scale"); + return (pow (10.0, arg / 40.0)); +} + +static gdouble +calculate_omega (gdouble freq, gint rate) +{ + GST_DEBUG ("calculate_omega"); + 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) +{ + GST_DEBUG ("calculate_bw"); + 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 (Gstaudioeq* audioeq, GstIirEqualizerBand * band) +{ + GST_DEBUG ("setup_peak_filter"); + //g_return_if_fail (GST_AUDIO_FILTER (equ)->format.rate); + + { + gdouble gain, omega, bw; + gdouble alpha, alpha1, alpha2, b0; + + gain = arg_to_scale (band->gain); + omega = calculate_omega (band->freq, audioeq->samplerate); + bw = calculate_bw (band, audioeq->samplerate); + 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 (Gstaudioeq* audioeq, GstIirEqualizerBand * band) +{ + GST_DEBUG ("setup_low_shelf_filter"); + //g_return_if_fail (GST_AUDIO_FILTER (equ)->format.rate); + + { + gdouble gain, omega, bw; + gdouble alpha, delta, b0; + gdouble egp, egm; + + gain = arg_to_scale (band->gain); + omega = calculate_omega (band->freq, audioeq->samplerate); + bw = calculate_bw (band, audioeq->samplerate); + 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 (Gstaudioeq* audioeq, GstIirEqualizerBand * band) +{ + GST_DEBUG ("setup_high_shelf_filter"); + { + gdouble gain, omega, bw; + gdouble alpha, delta, b0; + gdouble egp, egm; + + gain = arg_to_scale (band->gain); + omega = calculate_omega (band->freq, audioeq->samplerate); + bw = calculate_bw (band, audioeq->samplerate); + 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 (Gstaudioeq* audioeq) +{ + GST_DEBUG ("set_passthrough"); + GstIirEqualizer* equ=&audioeq->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 (audioeq), passthrough); + GST_DEBUG ("Passthrough mode: %d\n", passthrough); +} + +/* Must be called with bands_lock and transform lock! */ +static void +update_coefficients (Gstaudioeq* audioeq) +{ + GST_DEBUG ("update_coefficients"); + GstIirEqualizer* equ=&audioeq->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 (audioeq, equ->bands[i]); + else if (equ->bands[i]->type == BAND_TYPE_LOW_SHELF) + setup_low_shelf_filter (audioeq, equ->bands[i]); + else + setup_high_shelf_filter (audioeq, equ->bands[i]); + } + + equ->need_new_coefficients = FALSE; +} + +/* Must be called with transform lock! */ +static void +alloc_history (GstIirEqualizer * equ) +{ + GST_DEBUG ("alloc_history"); + /* free + alloc = no memcpy */ + g_free (equ->history); + equ->history = + g_malloc0 (equ->history_size * GST_AUDIO_FILTER_CHANNELS(&equ->audiofilter) * + equ->freq_band_count); +} +void +gst_audioeq_band_set_property(Gstaudioeq * audioeq) +{ + GST_DEBUG ("gst_audioeq_band_set_property"); + GstIirEqualizer *equ = &audioeq->equ; + gshort i ; + for ( i = 0; i < DEFAULT_CUSTOM_EQ_NUM; i++){ + GST_DEBUG ("gain = %lf -> %d", equ->bands[i]->gain, audioeq->custom_eq[i] ); + if (audioeq->custom_eq[i] != equ->bands[i]->gain) { + equ->bands[i]->gain = audioeq->custom_eq[i]; + GST_DEBUG("changed gain = %lf ", equ->bands[i]->gain); + g_object_notify (G_OBJECT (equ->bands[i]), "gain"); + } + } +} + +void +gst_iir_equalizer_compute_frequencies (Gstaudioeq * audioeq, guint new_count) +{ + GST_DEBUG ("gst_iir_equalizer_compute_frequencies"); + + GstIirEqualizer *equ = &audioeq->equ; + guint old_count, i; + gdouble freq0, freq1, step; + gchar name[20]; + gchar *old_name = NULL; + GST_DEBUG ("gst_iir_equalizer_compute_frequencies before calling equalizer object"); + if (equ->freq_band_count == new_count) + return; + + GST_DEBUG ("gst_iir_equalizer_compute_frequencies equalizer object"); + + BANDS_LOCK (equ); + GST_DEBUG ("gst_iir_equalizer_compute_frequencies 1"); + if (G_UNLIKELY (equ->freq_band_count == new_count)) { + BANDS_UNLOCK (equ); + return; + } + GST_DEBUG ("gst_iir_equalizer_compute_frequencies 2"); + 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++) { + equ->bands[i] = g_object_new (GST_TYPE_IIR_EQUALIZER_BAND, NULL); + /* otherwise they get names like 'iirequalizerband5' */ + sprintf (name, "band%u", i); + gst_object_set_name (GST_OBJECT (equ->bands[i]), name); + GST_DEBUG ("adding band[%d]=%p", i, equ->bands[i]); + + gst_object_set_parent (GST_OBJECT (equ->bands[i]), GST_OBJECT (audioeq)); + gst_child_proxy_child_added (GST_CHILD_PROXY (audioeq), + 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]); + old_name = gst_object_get_name(GST_OBJECT(equ->bands[i])); + gst_child_proxy_child_removed (GST_CHILD_PROXY (audioeq), + G_OBJECT (equ->bands[i]), old_name); + g_free(old_name); + gst_object_unparent (GST_OBJECT (equ->bands[i])); + equ->bands[i] = NULL; + } + } + + alloc_history (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"); + + 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); + +#ifdef AUDIOEQ_REDUCE_MEMCPY +static GstFlowReturn +gst_audioeq_transform_ip (GstBaseTransform * base, GstBuffer * buf) +{ + GST_DEBUG ("gst_audioeq_transform_ip"); + Gstaudioeq *audioeq = GST_AUDIOEQ(base); + GstIirEqualizer *equ = &audioeq->equ; + GstMapInfo buf_info = GST_MAP_INFO_INIT; + + equ->history_size = history_size_gint16; + equ->process = gst_iir_equ_process_gint16; + g_free (equ->history); + equ->history = g_malloc0 (equ->history_size * audioeq->channels * equ->freq_band_count); + GstClockTime timestamp; + + if (G_UNLIKELY (audioeq->channels < 1 || equ->process == NULL)) { + GST_DEBUG ("gst_audioeq_transform_ip return GST_FLOW_NOT_NEGOTIATED;"); + if (G_UNLIKELY (equ->process == NULL)) + GST_DEBUG ("gst_audioeq_transform_ip equ->process "); + if (G_UNLIKELY (audioeq->channels < 1)) + GST_DEBUG ("gst_audioeq_transform_ip audioeq->channels"); + return GST_FLOW_NOT_NEGOTIATED; + } + GST_DEBUG ("gst_audioeq_transform_ip BANDS_LOCK (equ);"); + BANDS_LOCK (equ); + if (equ->need_new_coefficients) { + GST_DEBUG ("gst_audioeq_transform_ip update_coefficients"); + update_coefficients (audioeq); + set_passthrough (audioeq); + } + BANDS_UNLOCK (equ); + + if (gst_base_transform_is_passthrough (base)) { + GST_DEBUG ("gst_audioeq_transform_ip gst_base_transform_is_passthrough return GST_FLOW_OK;"); + return GST_FLOW_OK; + } + timestamp = GST_BUFFER_TIMESTAMP (buf); + timestamp = + gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp); + + if (GST_CLOCK_TIME_IS_VALID (timestamp)) + gst_object_sync_values (GST_OBJECT (audioeq), timestamp); + GST_DEBUG (" equ->process ++"); + gst_buffer_map(buf, &buf_info, GST_MAP_READWRITE); + equ->process (equ, buf_info.data, buf_info.size, + audioeq->channels); + gst_buffer_unmap(buf, &buf_info); + GST_DEBUG (" equ->process --"); + GST_DEBUG ("gst_audioeq_transform_ip return GST_FLOW_OK;"); + return GST_FLOW_OK; +} +#endif + +static gboolean +gst_audioeq_set_caps (GstBaseTransform * base, GstCaps * incaps, + GstCaps * outcaps) +{ + GST_DEBUG ("gst_audioeq_set_caps"); + Gstaudioeq *audioeq = GST_AUDIOEQ(base); + GstStructure *ins; + GstPad *pad; + gint samplerate; + gint channels; + gshort old_samplerate; + gshort old_channels; + + pad = gst_element_get_static_pad(GST_ELEMENT(audioeq), "src"); + + /* forward-negotiate */ + if(!gst_pad_set_caps(pad, incaps)) { + gst_object_unref(pad); + return FALSE; + } + + /* negotiation succeeded, so now configure ourselves */ + ins = gst_caps_get_structure(incaps, 0); + + /* get samplerate from caps & convert */ + old_samplerate = audioeq->samplerate; + old_channels = audioeq->channels; + gst_structure_get_int(ins, "rate", &samplerate); + switch (samplerate) { + case 48000: + audioeq->samplerate = SAMPLERATE_48000Hz; + break; + case 44100: + audioeq->samplerate = SAMPLERATE_44100Hz; + break; + case 32000: + audioeq->samplerate = SAMPLERATE_32000Hz; + break; + case 24000: + audioeq->samplerate = SAMPLERATE_24000Hz; + break; + case 22050: + audioeq->samplerate = SAMPLERATE_22050Hz; + break; + case 16000: + audioeq->samplerate = SAMPLERATE_16000Hz; + break; + case 12000: + audioeq->samplerate = SAMPLERATE_12000Hz; + break; + case 11025: + audioeq->samplerate = SAMPLERATE_11025Hz; + break; + case 8000: + audioeq->samplerate = SAMPLERATE_8000Hz; + break; + default: + if (samplerate < 8000) { + audioeq->samplerate = SAMPLERATE_8000Hz; + } else if (samplerate > 48000) { + audioeq->samplerate = SAMPLERATE_48000Hz; + } + break; + } + /* get number of channels from caps */ + gst_structure_get_int(ins, "channels", &channels); + audioeq->channels = (gshort)channels; + + if ((old_samplerate != audioeq->samplerate) + || (old_channels != audioeq->channels)) { + audioeq->need_update_filter = TRUE; + } + + gst_object_unref (pad); + + return TRUE; +} + +static void +gst_audioeq_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GST_DEBUG ("gst_audioeq_set_property"); + Gstaudioeq *audioeq = GST_AUDIOEQ (object); + GstIirEqualizer *equ = &audioeq->equ; + gshort *pointer; + + switch (prop_id) { + + case PROP_FILTER_ACTION: + audioeq->filter_action = g_value_get_uint(value); + BANDS_LOCK(equ); + equ->need_new_coefficients = TRUE; + BANDS_UNLOCK(equ); + break; + + case PROP_CUSTOM_EQ: + pointer = g_value_get_pointer(value); + if (pointer) { + memcpy(audioeq->custom_eq, pointer, sizeof(gint) * CUSTOM_EQ_BAND_MAX); + if (audioeq->filter_action == FILTER_ADVANCED_SETTING) { + BANDS_LOCK(equ); + equ->need_new_coefficients = TRUE; + gst_audioeq_band_set_property(audioeq); + BANDS_UNLOCK(equ); + } + } + break; + + default: + break; + } + GST_DEBUG ("gst_audioeq_set_property need_update_filter %d", audioeq->need_update_filter); +} + +static void +gst_audioeq_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) +{ +GST_DEBUG ("gst_audioeq_get_property"); + + Gstaudioeq *audioeq = GST_AUDIOEQ (object); + GstIirEqualizer *equ = &audioeq->equ; + gshort i; + gdouble widtharr[DEFAULT_CUSTOM_EQ_NUM],freqarr[DEFAULT_CUSTOM_EQ_NUM]; + + switch (prop_id) { + case PROP_FILTER_ACTION: + g_value_set_uint(value, audioeq->filter_action); + break; + + case PROP_CUSTOM_EQ: + g_value_set_pointer(value, audioeq->custom_eq); + break; + + case PROP_CUSTOM_EQ_NUM: + g_value_set_uint(value, DEFAULT_CUSTOM_EQ_NUM); + break; + + case PROP_CUSTOM_EQ_FREQ: + for(i=0;ibands[i]->freq; + } + g_value_set_pointer(value, &freqarr); + break; + + case PROP_CUSTOM_EQ_WIDTH: + for(i=0;ibands[i]->width; + } + g_value_set_pointer(value, &widtharr); + break; + + default: + break; + } +} + +static gboolean +gst_iir_equalizer_setup (GstAudioFilter * audio, GstAudioRingBufferSpec * fmt) +{ +GST_DEBUG ("gst_iir_equalizer_setup"); + GstIirEqualizer *equ = GST_IIR_EQUALIZER (audio); + + switch (fmt->type) { + case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW: + switch (fmt->info.finfo->width) { + case 16: + equ->history_size = history_size_gint16; + equ->process = gst_iir_equ_process_gint16; + break; + case 32: + equ->history_size = history_size_gfloat; + equ->process = gst_iir_equ_process_gfloat; + break; + case 64: + equ->history_size = history_size_gdouble; + equ->process = gst_iir_equ_process_gdouble; + break; + default: + return FALSE; + } + break; + default: + return FALSE; + } + + alloc_history (equ); + return TRUE; +} + + +static gboolean +plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT(gst_audioeq_debug, "audioeq", 0, "Audio Equalizer Plugin"); + GST_DEBUG ("audioeq plugin_init "); + return gst_element_register(plugin, "audioeq", GST_RANK_NONE, GST_TYPE_AUDIOEQ); +} + + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + audioeq, + "Audio Equalizer Plugin", + plugin_init, + VERSION, + "LGPL", + "gst-plugins-ext", + "https://www.tizen.org/") diff --git a/audioeq/src/gstaudioeq.h b/audioeq/src/gstaudioeq.h new file mode 100644 index 0000000..2b698e0 --- /dev/null +++ b/audioeq/src/gstaudioeq.h @@ -0,0 +1,127 @@ +/* + * audioeq + * + * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Aditi Narula + * + * 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_AUDIOEQ_H__ +#define __GST_AUDIOEQ_H__ + +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_AUDIOEQ \ + (gst_audioeq_get_type()) +#define GST_AUDIOEQ(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIOEQ,Gstaudioeq)) +#define GST_audioeq_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIOEQ,GstaudioeqClass)) +#define GST_IS_AUDIOEQ(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIOEQ)) +#define GST_IS_AUDIOEQ_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIOEQ)) +#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)) + +typedef struct _Gstaudioeq Gstaudioeq; +typedef struct _GstaudioeqClass GstaudioeqClass; +typedef struct _GstIirEqualizer GstIirEqualizer; +typedef struct _GstIirEqualizerClass GstIirEqualizerClass; +typedef struct _GstIirEqualizerBand GstIirEqualizerBand; + +#define CUSTOM_EQ_BAND_MAX 9 + +#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; +}; + + + +struct _Gstaudioeq +{ + GstBaseTransform element; + + guint samplerate; + guint channels; + + /* properties */ + guint filter_action; + gint custom_eq[CUSTOM_EQ_BAND_MAX]; + gboolean need_update_filter; + GstIirEqualizer equ; +}; + +struct _GstaudioeqClass +{ + GstAudioFilterClass parent_class; +}; + +void gst_iir_equalizer_compute_frequencies (Gstaudioeq * audioeq, guint new_count); + +GType gst_iir_equalizer_get_type(void); + +GType gst_audioeq_get_type (void); + +G_END_DECLS + +#endif /* __GST_AUDIOEQ_H__ */ + diff --git a/audiotp/Makefile.am b/audiotp/Makefile.am new file mode 100755 index 0000000..308a09c --- /dev/null +++ b/audiotp/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/audiotp/src/Makefile.am b/audiotp/src/Makefile.am new file mode 100755 index 0000000..436666c --- /dev/null +++ b/audiotp/src/Makefile.am @@ -0,0 +1,26 @@ +# plugindir is set in configure + +############################################################################## +# change libgstplugin.la to something more suitable, e.g. libmysomething.la # +############################################################################## +plugin_LTLIBRARIES = libgstaudiotp.la + +############################################################################## +# for the next set of variables, rename the prefix if you renamed the .la, # +# e.g. libgstplugin_la_SOURCES => libmysomething_la_SOURCES # +# libgstplugin_la_CFLAGS => libmysomething_la_CFLAGS # +# libgstplugin_la_LIBADD => libmysomething_la_LIBADD # +# libgstplugin_la_LDFLAGS => libmysomething_la_LDFLAGS # +############################################################################## + +# sources used to compile this plug-in +libgstaudiotp_la_SOURCES = gstaudiotp.c + +# flags used to compile this plugin +# add other _CFLAGS and _LIBS as needed +libgstaudiotp_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) +libgstaudiotp_la_LIBADD = $(GST_LIBS) $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) +libgstaudiotp_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +# headers we need but don't want installed +noinst_HEADERS = gstaudiotp.h \ No newline at end of file diff --git a/audiotp/src/gstaudiotp.c b/audiotp/src/gstaudiotp.c new file mode 100644 index 0000000..c5b3879 --- /dev/null +++ b/audiotp/src/gstaudiotp.c @@ -0,0 +1,559 @@ +/* + * audiotp + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * 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 "gstaudiotp.h" +#include + +/*** GSTREAMER PROTOTYPES *****************************************************/ + +#define STATIC_CAPS \ +GST_STATIC_CAPS ( \ + GST_AUDIO_CAPS_MAKE(GST_AUDIO_FORMATS_ALL) \ +) + +/* Element sink pad template */ +static GstStaticPadTemplate gst_audiotp_sink_template = GST_STATIC_PAD_TEMPLATE ( + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + STATIC_CAPS); + +/* Element Source Pad template */ +static GstStaticPadTemplate gst_audiotp_src_template = GST_STATIC_PAD_TEMPLATE ( + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + STATIC_CAPS); + + +//////////////////////////////////////////////////////// +// Gstreamer Base Prototype // +//////////////////////////////////////////////////////// + +GST_DEBUG_CATEGORY_STATIC(gst_audiotp_debug); +#define GST_CAT_DEFAULT gst_audiotp_debug +#define _do_init(bla) \ + GST_DEBUG_CATEGORY_INIT(GST_CAT_DEFAULT, "audiotp", 0, "Audio trickplay plugin"); \ + GST_DEBUG("audiotp is registered"); + +G_DEFINE_TYPE_WITH_CODE(Gstaudiotp, gst_audiotp, GST_TYPE_ELEMENT, _do_init(G_TYPE_INVALID)); + +static void gst_audiotp_base_init(gpointer klass); +static void gst_audiotp_class_init(GstaudiotpClass *klass); +static void gst_audiotp_init(Gstaudiotp *dec); +static GstFlowReturn gst_audiotp_chain(GstPad *pad, GstObject *parent, GstBuffer *buf); +static GstStateChangeReturn gst_audiotp_change_state(GstElement *element, GstStateChange transition); +static void gst_audiotp_finalize(GObject *object); +static gboolean gst_audiotp_sink_event (GstPad *pad, GstObject *parent, GstEvent *event); +static GstFlowReturn gst_audiotp_push_silent_frame (Gstaudiotp *audiotp, GstBuffer *MetaDataBuf); + + + +//////////////////////////////////////////////////////// +// Gstreamer Base Functions // +//////////////////////////////////////////////////////// + +/** + ** + ** Description: The element details and pad templates are registered with the plugin + ** In Params : @ gclass instance of Element class + ** return : None + ** Comments : 1. Adding templates of source and sink pad to element + ** 2. Setting element class deatils to element + ** + */ +static void +gst_audiotp_base_init(gpointer klass) +{ +} + + +/** + ** + ** Description: Initialization of the Element Class + ** In Param : @ gclass instance of Element class + ** return : None + ** Comments : 1. Overwriting base class virtual functions + ** 2. Installing the properties of the element + ** + */ +static void +gst_audiotp_class_init(GstaudiotpClass *klass) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS(klass); + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + + gobject_class->finalize = gst_audiotp_finalize; + gst_element_class_add_pad_template(gstelement_class, gst_static_pad_template_get(&gst_audiotp_sink_template)); + gst_element_class_add_pad_template(gstelement_class, gst_static_pad_template_get(&gst_audiotp_src_template)); + gst_element_class_set_static_metadata(gstelement_class, "Audio timestamp reversal plugin", + "Utility/Audio", + "Reverses audio timestamps for reverse playback", + "Samsung Electronics "); + gstelement_class->change_state = GST_DEBUG_FUNCPTR(gst_audiotp_change_state); +} + + +/** + ** + ** Description: Initialization of the Element instance + ** In Params : @ audio tp element instance + ** @ gclass instance of Element class + ** return : None + ** Comments : 1. Creating new source & sink pads using templates + ** 2. Setting the callback functions to the pads + ** 3. Local data initialization. + ** + */ +static void +gst_audiotp_init(Gstaudiotp *audiotp) +{ + + audiotp->sinkpad = gst_pad_new_from_static_template(&gst_audiotp_sink_template, "sink"); + audiotp->srcpad = gst_pad_new_from_static_template(&gst_audiotp_src_template, "src"); + + gst_pad_set_chain_function (audiotp->sinkpad, GST_DEBUG_FUNCPTR(gst_audiotp_chain)); + gst_pad_set_event_function (audiotp->sinkpad, GST_DEBUG_FUNCPTR(gst_audiotp_sink_event)); + + gst_pad_use_fixed_caps(audiotp->srcpad); + + gst_element_add_pad(GST_ELEMENT(audiotp), audiotp->sinkpad); + gst_element_add_pad(GST_ELEMENT(audiotp), audiotp->srcpad); + + audiotp->reverse = g_queue_new (); + audiotp->head_prev = GST_CLOCK_TIME_NONE; + audiotp->tail_prev = GST_CLOCK_TIME_NONE; + +} + + +/** + ** + ** Description: Finalization of the Element instance (object) + ** In Params : @ audiotp element instance in the form of GObject + ** return : None + ** Comments : 1. Local data Deinitialization. + ** + ** + */ +static void +gst_audiotp_finalize(GObject *object) +{ + Gstaudiotp *audiotp = GST_AUDIOTP(object); + + while (!g_queue_is_empty (audiotp->reverse)) { + GstMiniObject *data = g_queue_pop_head (audiotp->reverse); + gst_mini_object_unref (data); + } + /* freeing dealy queue */ + g_queue_free(audiotp->reverse); + audiotp->reverse = NULL; + + G_OBJECT_CLASS(gst_audiotp_parent_class)->finalize(object); +} + + +/** + ** + ** Description: Callback function when the element's state gets changed + ** In Params : @ audiotp plugin element + ** @ type of state change + ** return : status of the state change processing + ** Comments : + ** + ** + */ +static GstStateChangeReturn +gst_audiotp_change_state(GstElement *element, GstStateChange transition) +{ + GstStateChangeReturn res = GST_FLOW_ERROR; + + 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; + } + + res = GST_ELEMENT_CLASS(gst_audiotp_parent_class)->change_state(element, transition); + if ( res != GST_STATE_CHANGE_SUCCESS ) { + GST_ERROR ("change state error in parent class\n"); + return GST_STATE_CHANGE_FAILURE; + } + + 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; +} + + +/** + ** + ** Description: Callback function when sinkpad gets an event + ** In Params : @ Sinkpad on which the event arrives + ** @ event type + ** return : TRUE/FALSE on success/failure of the event processing. + ** Comments : 1. Process the event and push it to the source pad. + ** + ** + */ +static gboolean +gst_audiotp_sink_event (GstPad *pad, GstObject *parent, GstEvent *event) +{ + Gstaudiotp *audiotp = NULL; + gboolean res = FALSE; + + audiotp = GST_AUDIOTP(parent); + + switch (GST_EVENT_TYPE(event)) { + /* Arrives whenever there is a jump in the normal playback. Ex:SEEK */ + case GST_EVENT_SEGMENT: { + const GstSegment *segment = NULL; + + GST_INFO_OBJECT (audiotp, "GST_EVENT_NEWSEGMENT"); + gst_event_parse_segment(event, &segment); + + if (segment->format != GST_FORMAT_TIME) { + GST_ERROR("Format is not supported\n"); + res = gst_pad_push_event(audiotp->srcpad, event); + goto done; + } + + GST_INFO_OBJECT (audiotp, "rate: %0.3f, arate: %0.3f\n", segment->rate, segment->applied_rate); + GST_INFO_OBJECT (audiotp, "start : %" GST_TIME_FORMAT, GST_TIME_ARGS(segment->start)); + GST_INFO_OBJECT (audiotp, "stop : %" GST_TIME_FORMAT, GST_TIME_ARGS(segment->stop)); + GST_INFO_OBJECT (audiotp, "time : %" GST_TIME_FORMAT, GST_TIME_ARGS(segment->time)); + + /* If we receive new_segment without FLUSH events, then we will push all the frame in queue */ + while (!g_queue_is_empty (audiotp->reverse)) { + GstBuffer *MetaDataBuf; + GstFlowReturn ret = GST_FLOW_OK; + if(audiotp->is_reversed) + MetaDataBuf = g_queue_pop_head (audiotp->reverse); + else + MetaDataBuf = g_queue_pop_tail (audiotp->reverse); + ret = gst_audiotp_push_silent_frame (audiotp, MetaDataBuf); + if (GST_FLOW_OK != ret) + { + GST_WARNING_OBJECT (audiotp, "pad_push returned = %s", gst_flow_get_name (ret)); + } + } + gst_segment_copy_into(segment, &audiotp->segment); + res = gst_pad_push_event(audiotp->srcpad, event); + break; + } + + /* Indication of the end of the stream */ + case GST_EVENT_EOS: { + /* queue all buffer timestamps till we receive next discontinuity */ + while (!g_queue_is_empty (audiotp->reverse)) { + GstBuffer *MetaDataBuf; + GstFlowReturn ret = GST_FLOW_OK; + if(audiotp->is_reversed) + MetaDataBuf = g_queue_pop_head (audiotp->reverse); + else + MetaDataBuf = g_queue_pop_tail (audiotp->reverse); + ret = gst_audiotp_push_silent_frame (audiotp, MetaDataBuf); + if (GST_FLOW_OK != ret) { + GST_WARNING_OBJECT (audiotp, "pad_push returned = %s", gst_flow_get_name (ret)); + } + } + + res = gst_pad_push_event(audiotp->srcpad, event); + break; + } + + /* Indication of the SEEK operation start */ + case GST_EVENT_FLUSH_START: { + GST_INFO_OBJECT (audiotp, "GST_EVENT_FLUSH_START"); + res = gst_pad_push_event(audiotp->srcpad, event); + break; + } + + /* Indication of the SEEK operation stop */ + case GST_EVENT_FLUSH_STOP: { + GST_INFO_OBJECT (audiotp, "GST_EVENT_FLUSH_STOP"); + /* make sure that we empty the queue */ + while (!g_queue_is_empty (audiotp->reverse)) { + GST_DEBUG_OBJECT (audiotp, "Flushing buffers in reverse queue...."); + gst_buffer_unref(g_queue_pop_head (audiotp->reverse)); + } + + res = gst_pad_push_event(audiotp->srcpad, event); + break; + } + + default: { + res = gst_pad_push_event(audiotp->srcpad, event); + break; + } + } + + done: + return res; +} + + +/** + ** + ** Description: Callback function when sinkpad gets a buffer (from the previous element) + ** In Params : @ Sinkpad on which the buffer arrives + ** @ input buffer + ** return : status of the buffer processing. + ** Comments : 1. Handle the buffer discontinuity ( in terms of tmestamp) + ** 2. Push or pop buffer based on discontinuity. + ** + ** + */ +static GstFlowReturn +gst_audiotp_chain(GstPad *pad, GstObject *parent, GstBuffer *buf) +{ + Gstaudiotp *audiotp = GST_AUDIOTP(parent); + GstFlowReturn ret = GST_FLOW_OK; + + if(buf == NULL) { + ret = GST_FLOW_ERROR; + goto error_exit; + } + + GST_LOG_OBJECT (audiotp, "Input buffer : ts =%" GST_TIME_FORMAT ", dur=%" GST_TIME_FORMAT ", size=%d %s", + GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buf)), + GST_TIME_ARGS(GST_BUFFER_DURATION(buf)), + gst_buffer_get_size(buf), GST_BUFFER_IS_DISCONT (buf) ? " - discont" :""); + + if (audiotp->segment.rate < 0.0) { + goto send_reverse; + } + + + /* Push the input data to the next element */ + ret = gst_pad_push(audiotp->srcpad, buf); + if (ret != GST_FLOW_OK ) { + GST_WARNING("failed to push buffer %p. reason: %s", buf, gst_flow_get_name (ret)); + buf = NULL; + goto error_exit; + } + return ret; + +send_reverse: + { + GstBuffer *MetaDataBuf = NULL; + GstClockTime headbuf_ts = GST_CLOCK_TIME_NONE; + GstClockTime tailbuf_ts = GST_CLOCK_TIME_NONE; + + /* Discont buffers is mostly due to seek, when buffers of seeked timestamp gets pushed */ + if (GST_BUFFER_IS_DISCONT(buf)) { + if(!g_queue_is_empty (audiotp->reverse)) { + GstBuffer *headbuf = (GstBuffer*) (audiotp->reverse->head->data); + GstBuffer *tailbuf = (GstBuffer*) (audiotp->reverse->tail->data); + + headbuf_ts = GST_BUFFER_TIMESTAMP(headbuf); + tailbuf_ts = GST_BUFFER_TIMESTAMP(tailbuf); + + GST_DEBUG_OBJECT(audiotp,"Headbuf ts =%" GST_TIME_FORMAT ", TailBuf ts =%" GST_TIME_FORMAT "", + GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(headbuf)), + GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(tailbuf))); + + /* Check if the decoder is already having the reversal logic */ + if(GST_BUFFER_TIMESTAMP(headbuf) > GST_BUFFER_TIMESTAMP(tailbuf)) { + GST_INFO_OBJECT (audiotp, "Buffers arrived in reverse order, audiotp NO NEED to reverse..."); + audiotp->is_reversed = TRUE; + } else { + GST_INFO_OBJECT (audiotp, "Buffers arrived in forward order, audiotp NEED to reverse..."); + audiotp->is_reversed = FALSE; + } + } + + while (!g_queue_is_empty (audiotp->reverse)) { + + if(audiotp->is_reversed) + MetaDataBuf = g_queue_pop_head (audiotp->reverse); + else + MetaDataBuf = g_queue_pop_tail (audiotp->reverse); + + if (NULL == MetaDataBuf) { + GST_ERROR_OBJECT (audiotp, "NULL pointer..."); + ret = GST_FLOW_ERROR; + goto error_exit; + } + + /* If buffers arrive in forward order, compare the MetaDatabuf with + * previous head buffer timestamp. + * If buffers arrive in reverse order, compare the MetaDataBuf with + * previous tail buffer timestamp */ + if((GST_BUFFER_TIMESTAMP(MetaDataBuf) < audiotp->head_prev && !audiotp->is_reversed) + || (GST_BUFFER_TIMESTAMP(MetaDataBuf) < audiotp->tail_prev && audiotp->is_reversed)) { + ret = gst_audiotp_push_silent_frame (audiotp, MetaDataBuf); + if (MetaDataBuf) { + gst_buffer_unref (MetaDataBuf); + MetaDataBuf = NULL; + } + + if (GST_FLOW_OK != ret) { + GST_WARNING_OBJECT (audiotp, "pad_push returned = %s", gst_flow_get_name (ret)); + if (buf) { + gst_buffer_unref (buf); + buf = NULL; + } + return ret; + } + } else { + GST_DEBUG_OBJECT(audiotp, "Dropping the buffer out of segment with time-stamp %"GST_TIME_FORMAT, + GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(MetaDataBuf))); + if (MetaDataBuf) { + gst_buffer_unref (MetaDataBuf); + MetaDataBuf = NULL; + } + } + } + + audiotp->head_prev = headbuf_ts; + audiotp->tail_prev = tailbuf_ts; + } + + MetaDataBuf = gst_buffer_new (); + if (NULL == MetaDataBuf) { + GST_ERROR_OBJECT (audiotp, "Failed to create memory..."); + ret = GST_FLOW_ERROR; + goto error_exit; + } + + /* copy buffer timestamps & FLAGS to metadata buffer */ + gst_buffer_copy_into (MetaDataBuf, buf, GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS, 0, 0); + gst_buffer_set_size(MetaDataBuf, gst_buffer_get_size(buf)); + GST_DEBUG_OBJECT (audiotp, "Pushing into reverse queue data of size: %d", gst_buffer_get_size(MetaDataBuf)); + + /* queue all buffer timestamps till we receive next discontinuity */ + g_queue_push_tail (audiotp->reverse, MetaDataBuf); + if (buf) { + gst_buffer_unref (buf); + buf = NULL; + } + return GST_FLOW_OK; + } + +#if 0 +/* May be useful in future */ +send_dummy: + { + + /* Resetting the buffer data to zero */ + memset(GST_BUFFER_DATA(buf), 0, GST_BUFFER_SIZE(buf)); + gst_buffer_set_caps(buf, GST_PAD_CAPS(audiotp->srcpad)); + + ret = gst_pad_push(audiotp->srcpad, buf); + if (ret != GST_FLOW_OK) { + GST_ERROR("Failed to push buffer. reason: %s\n", gst_flow_get_name(ret)); + buf = NULL; + goto error_exit; + } + return GST_FLOW_OK; + } +#endif + +error_exit: + + GST_WARNING_OBJECT(audiotp, "Returning from audiotp's chain with reason - %s", gst_flow_get_name (ret)); + if (buf) { + gst_buffer_unref (buf); + buf = NULL; + } + return ret; +} + + +static GstFlowReturn +gst_audiotp_push_silent_frame (Gstaudiotp *audiotp, GstBuffer *MetaDataBuf) +{ + + GstBuffer *out = NULL; + GstMapInfo out_info = GST_MAP_INFO_INIT; + GstFlowReturn ret = GST_FLOW_OK; + + out = gst_buffer_new_and_alloc(gst_buffer_get_size(MetaDataBuf)); + if(out == NULL) { + GST_ERROR_OBJECT (audiotp, "Failed to allocate memory..."); + return GST_FLOW_ERROR; + } + + /* Memset the data of the out buffer so that silent frame is sent */ + gst_buffer_map(out, &out_info, GST_MAP_WRITE); + memset(out_info.data, 0, out_info.maxsize); + gst_buffer_unmap(out, &out_info); + + gst_buffer_copy_into(out, MetaDataBuf, GST_BUFFER_COPY_FLAGS, 0, 0); + GST_BUFFER_OFFSET (out) = GST_BUFFER_OFFSET_END (out) = 0; + gst_buffer_set_size(out, gst_buffer_get_size(MetaDataBuf)); + GST_BUFFER_TIMESTAMP(out) = GST_BUFFER_TIMESTAMP(MetaDataBuf); + GST_BUFFER_DURATION(out) = GST_BUFFER_DURATION(MetaDataBuf); + + GST_LOG_OBJECT(audiotp, "Out buffer ts =%" GST_TIME_FORMAT ", dur=%" GST_TIME_FORMAT ", size=%d", + GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(out)), + GST_TIME_ARGS(GST_BUFFER_DURATION(out)), + gst_buffer_get_size(out)); + + ret = gst_pad_push(audiotp->srcpad, out); + if (ret != GST_FLOW_OK) { + GST_ERROR_OBJECT (audiotp, "Failed to push buffer. reason: %s\n", gst_flow_get_name(ret)); + out = NULL; + } + + return ret; +} + +static gboolean +gst_audiotp_plugin_init (GstPlugin *plugin) +{ + if (!gst_element_register (plugin, "audiotp", GST_RANK_PRIMARY, gst_audiotp_get_type())) { + return FALSE; + } + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + audiotp, + "Audio trickplay plugin", + gst_audiotp_plugin_init, + VERSION, + "LGPL", + "Samsung Electronics Co", + "http://www.samsung.com") diff --git a/audiotp/src/gstaudiotp.h b/audiotp/src/gstaudiotp.h new file mode 100755 index 0000000..0b3dc92 --- /dev/null +++ b/audiotp/src/gstaudiotp.h @@ -0,0 +1,69 @@ +/* + * audiotp + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * 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_AUDIOTP_H__ +#define __GST_AUDIOTP_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_AUDIOTP (gst_audiotp_get_type()) +#define GST_AUDIOTP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIOTP,Gstaudiotp)) +#define GST_AUDIOTP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIOTP,GstaudiotpClass)) +#define GST_AUDIOTP_GET_CLASS(klass) (G_TYPE_INSTANCE_GET_CLASS((klass),GST_TYPE_AUDIOTP,GstaudiotpClass)) +#define GST_IS_AUDIOTP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIOTP)) +#define GST_IS_AUDIOTP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIOTP)) +#define GST_AUDIOTP_CAST(obj) ((Gstaudiotp *)(obj)) + +typedef struct _Gstaudiotp Gstaudiotp; +typedef struct _GstaudiotpClass GstaudiotpClass; + +struct _Gstaudiotp +{ + GstElement element; + GstPad *sinkpad; + GstPad *srcpad; + GQueue *reverse; /* used in reverse trickplay */ + GstSegment segment; + + /* Flag to indicate the new buffer recieved is discountinued in + its time-stamp */ + gboolean discont; + gboolean is_reversed; + GstClockTime head_prev; + GstClockTime tail_prev; +}; + +struct _GstaudiotpClass +{ + GstElementClass parent_class; +}; + +GType gst_audiotp_get_type (void); + +G_END_DECLS + +#endif /* __GST_AUDIOTP_H__ */ \ No newline at end of file diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..d4c6d40 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# you can either set the environment variables AUTOCONF and AUTOMAKE +# to the right versions, or leave them unset and get the RedHat 7.3 defaults + +aclocal -I m4 -I common/m4 +libtoolize --copy --force +autoheader +autoconf +automake --add-missing --copy --foreign + +echo "Now type 'make' to compile $package." + diff --git a/autoregen.sh b/autoregen.sh new file mode 100755 index 0000000..c67a299 --- /dev/null +++ b/autoregen.sh @@ -0,0 +1,2 @@ +#!/bin/sh +./autogen.sh $@ diff --git a/common/ChangeLog b/common/ChangeLog new file mode 100755 index 0000000..72f093a --- /dev/null +++ b/common/ChangeLog @@ -0,0 +1,1343 @@ +2008-03-07 Edward Hervey + + * m4/gtk-doc.m4: (GTK_DOC_CHECK): + The previous commit to this file by Stefan Kost mentionned checking for + SED, but NOT checking for gtkdoc-check (wth is that doing there ??). + Therefore, removing the check for gtkdoc-check + +2008-03-03 David Schleef + + * m4/ax_create_stdint_h.m4: Oops, checked in the wrong copy of + this file. (Update from upstream) + +2008-03-03 David Schleef + + * m4/ax_create_stdint_h.m4: Update from upstream. Fixes a bug + compiling with MSVC. + +2008-03-03 Edward Hervey + + * m4/pkg.m4: + Allow override of pkg-config results, as proposed by configure --help. + This is in fact just a backport from upstream pkg.m4. + Fixes #518892 + +2008-03-03 Peter Kjellerstedt + + * ChangeLog: + Changelog surgery of my previous commit to add bugzilla reference. + * m4/gst-args.m4: + Add AG_GST_CHECK_PLUGIN and AG_GST_DISABLE_PLUGIN to make it easier + to include and exclude plug-ins without external references, i.e., + plug-ins listed in GST_PLUGINS_SELECTED. (#498222) + +2008-03-03 Sebastian Dröge + + * gst.supp: + Add another glibc suppression. + +2008-02-29 Peter Kjellerstedt + + * m4/gst-feature.m4: + Make the comment before defines generated via AG_GST_CHECK_FEATURE + look nicer. (#498222) + +2008-02-26 Jan Schmidt + + * m4/Makefile.am: + * m4/as-gcc-inline-assembly.m4: + Add Dave Schleef's GCC inline assembly detection macro + for using in gst-plugins-good in the goom 2k4 plugin. + +2008-02-25 Andy Wingo + + * gst-autogen.sh: Instead of only passing certain arguments to + configure, pass anything that we didn't handle. Much friendlier. + Fixes #34412. + +2008-02-23 Jan Schmidt + + * m4/gst-error.m4: + Store the detected compiler flags into ERROR_CFLAGS rather than + ERROR_CXXFLAGS, and use the macro that checks the C compiler, not + the C++ one. + +2008-02-23 Tim-Philipp Müller + + * m4/gst-error.m4: + Reflow checks for additional warning flags so they're not + nested, which fixes the result reporting in the configure + output. + +2008-02-22 Tim-Philipp Müller + + * m4/as-compiler-flag.m4: + Add AS_CXX_COMPILER_FLAG + + * m4/gst-error.m4: + Add AG_GST_SET_ERROR_CXXFLAGS (Forte bits need testing) + +2008-02-22 Tim-Philipp Müller + + * gtk-doc-plugins.mak: + Add 'check-inspected-versions' target; this helps identify + files that should have been removed or where the version + number should (ideally) be updated before a release + (which doesn't happen automatically if the releaser doesn't + build that plugin locally). Not adding at a distcheck hook + yet though, because it's not really that important and would + probably also be a problem on buildbots. + +2008-02-22 Sebastian Dröge + + * gst.supp: + Add even more glibc 2.7 suppressions. + +2008-02-22 Sebastian Dröge + + * gst.supp: + Add another suppression for GLib caching some values after + the first call. + +2008-02-12 Sebastian Dröge + + Patch by: + Tim Mooney + + * m4/gst-error.m4: + Use no%E_MACRO_REDEFINED on Solaris to prevent compiler warnings. + Fixes bug #515905. + +2008-02-11 Sebastian Dröge + + * gst.supp: + Add a few more glibc 2.7 suppressions to make the avisubtitle unit + test valgrind clean. Fixes bug #515703. + +2008-02-08 Stefan Kost + + * ChangeLog: + Changelog surgery for last commit. + +2008-02-08 Stefan Kost + + * m4/gtk-doc.m4: + Conditionally check for SED. Also sync a bit with upstream macro. + +2008-02-08 Stefan Kost + + * gtk-doc-plugins.mak: + * gtk-doc.mak: + Use '$(SED)' instead of 'sed'. Don't use -i for in-place as its gnu + only, move to a temp file instead. + +2008-02-06 Stefan Kost + + * gtk-doc-plugins.mak: + * gtk-doc.mak: + As our docs are versioned, we need to patch the index.sgml file to have + correct paths there, unless we also want to fork gtk-doc's xsl (which + we don't). This hopefully fixes xrefs between modules. + +2008-02-02 Sebastian Dröge + + * m4/gst-feature.m4: + Use printf instead of echo as "echo -e" isn't POSIX and doesn't work + with strict POSIX shells like tcsh or dash and also not every platform + has a /bin/echo that supports it. + +2008-01-24 Stefan Kost + + * ChangeLog: + ChangeLog surgery. + + * gstdoc-scangobj: + Sync the object scanner with gtk-doc fixes. Update args and hierarchy + files. + +2008-01-20 Sebastian Dröge + + * check.mak: + * coverage/lcov.mak: + * gtk-doc-plugins.mak: + * release.mak: + Use $(MAKE) instead of make to fix the build if GNU make is called + something else on the system. + + * m4/as-docbook.m4: + Fix path for docbook.xsl if we have no /etc/xml/catalog and add a + docbook-xsl search path for FreeBSD. + +2008-01-18 Sebastian Dröge + + * gst.supp: + Add a suppression for a glibc bug: + http://valgrind.org/docs/manual/faq.html#faq.exit_errors> + +2008-01-18 Sebastian Dröge + + * gst.supp: + Add some more glibc 2.7 suppressions and make the GLib suppressions + for the home/tmp/etc directory caching a bit more generic. + +2008-01-18 Sebastian Dröge + + * gst.supp: + Add some glibc 2.7 supressions as found on Debian/unstable. + +2008-01-14 Jan Schmidt + + * download-translations: + Apparently I have problems with leaving things commented out when + I edit shell scripts. + +2008-01-12 Jan Schmidt + + * download-translations: + Remove bash-isms + +2008-01-12 Jan Schmidt + + * check-exports: + Restore the cleanup rm of our tmp file which I didn't mean to leave + commented out. + +2008-01-12 Jan Schmidt + + * check-exports: + Fixes to make check-export work on both Solaris and Linux + + * m4/gst-error.m4: + Disable extra warning category (argument mismatch) as an error + on Forte, as it prevents the libcheck fail_if macros from compiling. + + * win32.mak: + Substitute the GStreamer version so things will keep working in 0.11 + +2008-01-11 Tim-Philipp Müller + + Patch by: Peter Kjellerstedt + + * m4/gst-glib2.m4: + * m4/gst-libxml2.m4: + Improve/fix output from configure if either glib-2.0 or + libxml2 are not installed (#498222). + +2008-01-09 Stefan Kost + + * coverage/lcov.mak: + Update coverage make-rules: use them conditionaly, use libtool mode + and use lcov to cleanup. + +2007-12-18 Sebastian Dröge + + * glib-gen.mak: + Also use #include "header" instead of #include
for the + headers that were used to generate the source files for the same + reason as below. + + Remove whitespace before #include. + +2007-12-18 Sebastian Dröge + + * glib-gen.mak: + Use #include "header" instead of #include
for the generated + enum C files as the file will always be in the same directory and + some compilers seem to be a bit strict about that unless . is added + to the include path. + + Include all headers that were used to generate the source files in + the C file as they're used there. + +2007-12-17 Tim-Philipp Müller + + * win32.mak: (win32), (win32defs), (win32crlf): + Make check for CR LF in Visual C++ 6.0 project files + work, based on patch by David Schleef (#496722, #393626). + +2007-12-17 Tim-Philipp Müller + + * Makefile.am: + Don't forget to dist the new win32.mak. + +2007-12-17 Tim-Philipp Müller + + * win32.mak: (win32), (win32defs): + Move common win32 Makefile foo into this new file. + +2007-12-15 Stefan Kost + + * gtk-doc-plugins.mak: + * gtk-doc.mak: + We should have never forked this that much :/. + +2007-12-13 Tim-Philipp Müller + + * check-exports: + Fix build on the ppc64 build bot. + +2007-12-13 Tim-Philipp Müller + + * check-exports: + Suppress more unintentional exports (too much hassle to rename them, + since the win32 project files would need changing too). + +2007-12-12 Tim-Philipp Müller + + * Makefile.am: + check-exports should be disted. + +2007-12-12 Tim-Philipp Müller + + * check-exports: + Add quick'n'dirty script to check the exported symbols of a library + against the symbols in the corresponding .def file (#493983). Based + on script by Ole André Vadla Ravnås. + +2007-11-06 Jan Schmidt + + * gtk-doc-plugins.mak: + Fix distcheck by making sure the types files are treated like the + other gtkdoc-scangobj generated files. + +2007-09-21 Sebastian Dröge + + * m4/gst-args.m4: + Let the AG_GST_ARG_ENABLE_EXPERIMENTAL macro default to disable + building of experimental plugins. Nobody uses it yet and the + --enable--experimental stuff from gst-plugins-good defaults to + disable too. + +2007-09-06 Tim-Philipp Müller + + * gtk-doc-plugins.mak: + Just use the normal 'check' target and avoid a circular + dependency. + +2007-09-06 Tim-Philipp Müller + + * gtk-doc-plugins.mak: + Add rule to error out if .hierarchy file contains tabs. + +2007-08-20 Tim-Philipp Müller + + * download-translations: + * po.mak: + If there are new languages, they need to be added to po/LINGUAS. + +2007-08-20 Tim-Philipp Müller + + * download-translations: + * po.mak: + Fix up 'download-po' a bit, so that we find new translations + for languages that aren't in our po/LINGUAS file yet too. + +2007-07-16 Jan Schmidt + + * gst.supp: + Add a suppression for GLib caching the tmp dir seen on an + Ubuntu Feisty system. + +2007-07-13 Jan Schmidt + + * m4/gst-feature.m4: + If we want to use 'echo -e', call /bin/echo instead of the shell's + since -e is a bash extension, and our /bin/sh might not be being + provided by bash. + +2007-07-01 Thomas Vander Stichele + + * po.mak: + Translation project has moved. Also, no idea how this used to + work given that we weren't downloading a .po file. + +2007-06-25 Stefan Kost + + * gst-xmlinspect.py: + * plugins.xsl: + Also extract element caps for plugin-docs. Fixes parts of #117692. + +2007-06-21 Tim-Philipp Müller + + Patch by: Andreas Schwab + + * m4/gst-feature.m4: + Fix quoting (#449493). + +2007-06-10 Sebastian Dröge + + * m4/gst-parser.m4: + Only generate the parser if bison >= 1.875 _and_ flex >= 2.5.31 is + installed and use pre-generated sources otherwise. Fixes bug #444820. + +2007-05-11 Michael Smith + + * gst.supp: + Suppression variant for our good friend the TLS leak, this time for + Ubuntu Feisty/x86. + +2007-05-09 Tim-Philipp Müller + + * gtk-doc-plugins.mak: + Fix make distcheck again; change some spaces to tabs in makefile. + +2007-04-29 Thomas Vander Stichele + + * gtk-doc-plugins.mak (-module): + Error out when the html build step gives warnings, so they get + fixed properly. + +2007-04-23 Stefan Kost + + * m4/gst-feature.m4: + Add macro AG_GST_PARSE_SUBSYSTEM_DISABLES that checks the defines in + the configuration header and AC_DEFINES the setings. + +2007-04-19 Sebastian Dröge + + Patch by: Vincent Torri + + * m4/gst-parser.m4: + Put the AC_MSG_RESULT output in brackets to get it properly written to + the terminal. + +2007-04-18 Sebastian Dröge + + * m4/gst-parser.m4: + Check for flex >= 2.5.31 and set GENERATE_PARSER if we have at least + that version. Otherwise use pre-generated parser sources as we can't + raise the required flex version. HAVE_MT_SAVE_FLEX is obsolete now + as we use a new enough flex version anyway. First part of #349180 + +2007-04-10 Thomas Vander Stichele + + * m4/gst-check.m4: + Allow pre-setting the GST(PB)_TOOLS/PLUGINS_DIR variables to help + builds against older GStreamer. + +2007-03-25 Sebastian Dröge + + * m4/gst-parser.m4: + Fix the flex version check. It ignored the micro version before. + +2007-03-09 Jan Schmidt + + * check.mak: + Use the same timeout when generating valgrind suppressions as + running the valgrind test. + + * gst.supp: + Add some more suppressions and stuff. + +2007-03-08 Jan Schmidt + + * check.mak: + Make sure GSlice is disabled when building suppressions too. + + * gst.supp: + Add around *850* lines of suppressions for one-time initialisations + inside libasound and gconf/bonobo/ORBit. I feel so dirty. + +2007-03-07 Jan Schmidt + + * gst.supp: + add a suppression for this GConf flup on the FC5 buildbot. + +2007-03-06 Jan Schmidt + + * gst.supp: + Make the suppression a little more generic, to catch the FC5 + backtrace too. + +2007-03-06 Jan Schmidt + + * gst.supp: + Add a suppression for libcdio 0.76. It leaks an internal struct + when the CD-ROM device is not accessible. + +2007-02-28 Thomas Vander Stichele + + * m4/gst-arch.m4: + Move a line that was in the wrong macro + +2007-02-28 Thomas Vander Stichele + + * m4/gst.m4: + Add + * m4/gst-arch.m4: + * m4/gst-args.m4: + * m4/gst-check.m4: + * m4/gst-debuginfo.m4: + * m4/gst-default.m4: + * m4/gst-doc.m4: + * m4/gst-error.m4: + * m4/gst-feature.m4: + * m4/gst-function.m4: + * m4/gst-gettext.m4: + * m4/gst-glib2.m4: + * m4/gst-libxml2.m4: + * m4/gst-parser.m4: + * m4/gst-plugin-docs.m4: + * m4/gst-plugindir.m4: + * m4/gst-valgrind.m4: + * m4/gst-x11.m4: + Convert all macros to use AG_GST style so we can properly warn + when they're missing if configure.ac calls AG_GST_INIT + Will require update in all GStreamer modules. + +2007-02-11 Stefan Kost + + * m4/gst-args.m4: + Remove 'enable' from configure switch description as this leads to + confusing lines like "disable enable builing ...". + * m4/gst-feature.m4: + Fix comment to sound less horrible. + +2007-02-07 Tim-Philipp Müller + + Patch by: Will Newton + + * m4/gst-check.m4: + Use $PKG_CONFIG rather than pkg-config directly, the one in our path + might not be the one we want, like when cross-compiling. Also, other + macros such as PKG_CHECK_MODULES use $PKG_CONFIG, so we should + probably too just for consistency. Fixes #405288. + +2007-01-08 Tim-Philipp Müller + + * m4/gst-parser.m4: + Need to use double square brackets again so m4 doesn't remove them + (fixes #378931). + + * m4/gst-args.m4: + Use double square brackets here as well, for the same reason. + +2007-01-05 Tim-Philipp Müller + + * m4/gst-parser.m4: + Use 'sed' rather than 'tr' to strip trailing letters from version + numbers, since 'tr' might not be available and we know sed is + (#378931). + +2006-10-21 Tim-Philipp Müller + + * check.mak: + Increase default timeout under valgrind, 60 is just too short and + some tests take a bit longer these days and not everyone has a + beefy machine. + +2006-09-29 Michael Smith + + * gst.supp: + More suppressions for edgy. + +2006-09-28 Jan Schmidt + + * m4/gst-glib2.m4: + Use gmodule-no-export-2.0.pc instead of gmodule-2.0.pc - we neither + want nor need --export-dynamic (which ends up making us export a bunch + of unneeded symbols) + +2006-09-14 Tim-Philipp Müller + + * gst.supp: + Some suppressions for the more recent ld.so in ubuntu edgy. + +2006-08-23 Tim-Philipp Müller + + * gst.supp: + Shorten function trail so the suppression works on + my ubuntu dapper system with core cvs as well. + +2006-07-28 Jan Schmidt + + * gst.supp: + Extra suppressions from my Ubuntu x86_64 machine + +2006-07-24 Tim-Philipp Müller + + Patch by: Frederic Peters + + * m4/gst-parser.m4: + Need to double square brackets in .m4 files. Should fix bison + version detection with version numbers like 1.23a (#348354). + +2006-07-24 Jan Schmidt + + * check.mak: + Valgrind fails to find tests written in tests/check/ directly (rather + than a subdir) - because valgrind gets run with a filename that + doesn't contain a relative path, it goes searching /usr/bin instead. + Run with ./.... to make things work either way. + + * gtk-doc-plugins.mak: + Add $(top_builddir)/src as a place to look for plugins + when building too, since that's where gst-template keeps things + +2006-07-23 Stefan Kost + + Patch by: Frederic Peters + + * m4/gst-parser.m4: + Fix bison detection (#348354) + +2006-07-21 Stefan Kost + + * m4/gst-parser.m4: + check for bison and flex + +2006-07-13 Thomas Vander Stichele + + * m4/gst-plugin-docs.m4: + remove the configure argument for enabling plugin doc build; + having gtk-doc enabled and pyxml present is enough of a trigger + +2006-07-03 Thomas Vander Stichele + + * coverage/lcov.mak: + fix up rules to work with gst-python as well + run "make lcov" to test and generate the reports + run "make lcov-reset" to redo it after that + +2006-07-02 Thomas Vander Stichele + + * Makefile.am: + * check.mak: + add an inspect target that inspects every element feature, + so we can have that added for coverage + * coverage/lcov.mak: + add support for lcov + +2006-07-02 Thomas Vander Stichele + + * m4/gst-args.m4: + when building with gcov, reset CFLAGS and friends to O0 + +2006-07-02 Thomas Vander Stichele + + * m4/gst-args.m4: + Find the gcov that matches the gcc version + Only allow gcov if we use gcc + +2006-07-02 Thomas Vander Stichele + + * Makefile.am: + * coverage/coverage-report-entry.pl: + * coverage/coverage-report.pl: + * coverage/coverage-report.xsl: + copy coverage reporting files from dbus + +2006-07-01 Thomas Vander Stichele + + * m4/gst-args.m4: + libtool strips gcov's -f flags, so libgcov does not get + linked in. Setting GCOV_LIBS with -lgcov fixes libtool's + stripping + also show what pkg-config-path we set + +2006-06-22 Tim-Philipp Müller + + Patch by: Peter Kjellerstedt + + * m4/gst-feature.m4: + Show list of plugins without external dependencies that + will not be built as well (#344136). + +2006-06-15 Tim-Philipp Müller + + * m4/gst-plugin-docs.m4: + add GST_PLUGIN_DOCS, which checks for everything needed + to build the plugin docs (namely gtk-doc and pyxml); also + adds a new --enable-plugin-docs configure switch; will + set ENABLE_PLUGIN_DOCS conditional for use in Makefile.am + files (see #344039). + +2006-06-11 Thomas Vander Stichele + + * m4/gst-check.m4: + add GST_PKG_CHECK_MODULES, which in the normal case of checking + for a dependency lib for a plug-in only needs two arguments + to do the right thing. + * m4/gst-feature.m4: + clean up output a little of feature checking; also deal with + non-plug-in feature checks + * m4/Makefile.am: + * m4/gst-gstreamer.m4: + remove this file; it's a useless check + +2006-06-06 Thomas Vander Stichele + + * m4/gst-arch.m4: + add PPC64 so we can have separate structure sizes for it + +2006-06-05 Edward Hervey + + * gtk-doc.mak: + Check for the proper .devhelp2 file to remove. + +2006-05-31 Thomas Vander Stichele + + * gtk-doc.mak: + allow a magic variable to suppress errors from docbuilding + +2006-05-30 Thomas Vander Stichele + + * gtk-doc.mak: + error out if gtkdoc-mktmpl finds unused declarations + +2006-05-28 Edward Hervey + + * gst.supp: + Reverting previous commit. That's good to know, Edward, but why ? + +2006-05-28 Edward Hervey + + * gst.supp: + Added suppresion for memleak in g_option_context_parse on fc5-64 + +2006-05-19 Thomas Vander Stichele + + * m4/gst-check.m4: + set GSTPB_PLUGINS_DIR just like GST_PLUGINS_DIR + +2006-05-18 Tim-Philipp Müller + + * check.mak: + Fix 'make help' in check directories, it should be + 'valgrind.gen-suppressions' not 'valgrind-gen-suppressions' + (not changing target to match help string on purpose to keep + scripts etc. functional). + +2006-05-18 Thomas Vander Stichele + + Patch by: Peter Kjellerstedt + + * m4/gst-arch.m4: + add support for CRIS and CRISv32. + +2006-05-17 Jan Schmidt + + * m4/gst-args.m4: + Fix the macros for command-line supplied package and origin names + so they don't end up being configure as "" (Fixes #341479) + +2006-05-14 Jan Schmidt + + * gtk-doc.mak: + Add uninstall rule to remove .devhelp2 files. + +2006-05-09 Edward Hervey + + * gst.supp: + Add suppression for GSlice version of + g_type_init calloc leak + +2006-04-05 Michael Smith + + * gst.supp: + Delete a bogus suppression for the registry code. + Generalise a suppression for a glib bug (see #337404) + +2006-04-04 Michael Smith + + * gst.supp: + Add a leak suppression: the existing glibc-doesn't-free-TLS one + wasn't triggering here. + +2006-04-04 Michael Smith + + * gst.supp: + Add some minimally-neccesary suppressions for my x86/dapper system. + +2006-04-01 Thomas Vander Stichele + + * plugins.xsl: + Do not display an origin link if origin does not start with http + See #323798 + +2006-04-01 Thomas Vander Stichele + + * m4/gst-args.m4: + * m4/gst-feature.m4: + add more macros + * m4/gst-x11.m4: + X11-related checks + +2006-04-01 Thomas Vander Stichele + + * m4/as-version.m4: + newer version + * m4/gst-args.m4: + * m4/gst-doc.m4: + update and add other macros to be shared across projects + +2006-03-24 Thomas Vander Stichele + + * gst.supp: + add a suppression for g_parse_debug_string + +2006-03-23 Stefan Kost + + * gstdoc-scangobj: + sync fully with gtkdoc-0.15 + +2006-03-23 Stefan Kost + + * gstdoc-scangobj: + * gtk-doc.mak: + sync a little with gtk-doc mainline + +2006-03-17 Wim Taymans + + * gst.supp: + add another clone suppression + change all glibc suppressions to match 2.3.* + +2006-03-09 Thomas Vander Stichele + + * m4/check.m4: + fix test so it actually works when the normal check is used + over debian's/ubuntu's + +2006-03-08 Jan Schmidt + + * check.mak: + Set G_SLICE=always-malloc when valgrinding tests + (closes #333272) + +2006-02-21 Jan Schmidt + + * m4/gst-glib2.m4: + Fix debug output when the GLib version prerequisite is not found + +2006-02-13 Andy Wingo + + * m4/check.m4: Hack around Debian/Ubuntu's broken installation of + the PIC version of check as libcheck_pic.a. Should work with + cross-compilation too. Grr. + +2006-02-06 Thomas Vander Stichele + + * m4/gst-default.m4: + switch to auto* sinks for defaults + +2006-02-02 Wim Taymans + + * check.mak: + add a .valgrind.gen-suppressions target to aid in generating + suppressions + * gst.supp: + add more repressions from my debian glibc as of today + +2006-02-02 Thomas Vander Stichele + + * gtk-doc-plugins.mak: + only add srcdir/gst if it exists + +2006-01-30 Thomas Vander Stichele + + * release.mak: + don't complain about disted enums in win32 + +2006-01-20 Thomas Vander Stichele + + * m4/gst-check.m4: + AC_SUBST CFLAGS and LIBS + do a non-command because something is stripping out our AC_SUBST + +2006-01-20 Thomas Vander Stichele + + * m4/gst-args.m4: + * m4/gst-valgrind.m4: + properly give a "no" result manually when providing a + not-found action to fix configure output + +2006-01-20 Thomas Vander Stichele + + * m4/pkg.m4: + update with a more recent version + +2006-01-07 Thomas Vander Stichele + + * gettext.patch: + make Makefile depend on LINGUAS, so rebuilds work when adding + a language + +2006-01-03 Michael Smith + + * check.mak: + Clarify error message from valgrind test runs. + +2005-12-16 Thomas Vander Stichele + + * m4/gst-arch.m4: + define HOST_CPU + +2005-11-29 Thomas Vander Stichele + + * check.mak: + add a valgrind-forever target for tests + +2005-11-28 Thomas Vander Stichele + + * check.mak: + when a "make test.check" run fails, make it rerun the test with + at least debug level 2 + +2005-11-14 Thomas Vander Stichele + + * m4/Makefile.am: + * m4/gst-check.m4: + fix check for base plugins + * m4/gst-default.m4: + add m4 to set default elements + +2005-10-18 Thomas Vander Stichele + + * m4/gst-check.m4: + check for tools correctly + +2005-10-18 Thomas Vander Stichele + + * gtk-doc.mak: + only enable breaking on new API when make distcheck passes, + not before + +2005-10-18 Thomas Vander Stichele + + * m4/gst-check.m4: + Resurrect Julien's dead body and wipe his mind clean + +2005-10-18 Thomas Vander Stichele + + * m4/gst-check.m4: + Kill Julien + +2005-10-17 Julien MOUTTE + + * m4/gst-check.m4: I know Thomas will kill me but this + ifelse statement seems incorrect as it is always setting + required to "yes". With this one it seems to work. Fixes + build of gst-plugins-base on my setup where gstreamer-check + is definitely not present/required. + +2005-10-18 Stefan Kost + + * gtk-doc.mak: + make build break on new api that has not been added to the + sections file + +2005-10-17 Thomas Vander Stichele + + * m4/gst-glib2.m4: + * m4/Makefile.am: + * m4/gst-check.m4: + add macro for easy checks for GStreamer libs + +2005-10-16 Thomas Vander Stichele + + * m4/gst-glib2.m4: + update, warn in error cases + +2005-10-16 Thomas Vander Stichele + + * m4/gst-error.m4: + add GST_SET_DEFAULT_LEVEL + +2005-10-16 Thomas Vander Stichele + + * m4/Makefile.am: + * m4/gst-gettext.m4: + remove the AM_GNU_GETTEXT* calls, they need to be in configure.ac + * m4/gst-glib2.m4: + clean up and re-use in core soon + * m4/gst-plugindir.m4: + macro to set up PLUGINDIR and plugindir define/var + +2005-10-15 Thomas Vander Stichele + + * m4/Makefile.am: + * m4/gst-gettext.m4: + add macro for setting up gettext + +2005-10-15 Thomas Vander Stichele + + * m4/gst-args.m4: + add some .m4's for argument checking that can be shared among modules + +2005-10-15 Thomas Vander Stichele + + * m4/as-libtool.m4: + set _LT_LDFLAGS + * m4/gst-libxml2.m4: + document + +2005-10-15 Thomas Vander Stichele + + * m4/gst-arch.m4: + indent a little + add AC_REQUIRE + * m4/gst-error.m4: + clean up + +2005-10-12 Thomas Vander Stichele + + * gst-autogen.sh: + update version detection expression to catch stuff like + Libtool (libtool15) 1.5.0 + +2005-10-11 Thomas Vander Stichele + + * gst.supp: + commit 6 new suppressions related to g_module_open; can these + really not be folded into one ? + +2005-10-11 Edward Hervey + + * gst.supp: + made the suppression more generic + Added pthread memleak suppresions + Added nss_parse_* memleak suppresion (used by g_option_context_parse) + +2005-10-11 Thomas Vander Stichele + + * check.mak: + be more strict, more leak resolution + * gst.supp: + clean up the g_type_init suppressions + +2005-10-07 Thomas Vander Stichele + + * m4/Makefile.am: + * m4/gst-valgrind.m4: + put the valgrind detection in an .m4 + +2005-09-29 Thomas Vander Stichele + + * check.mak: + add some more targets, like "help", but also more intensive tests + +2005-09-23 Thomas Vander Stichele + + * gtk-doc.mak: + make certain doc warnings fatal so people maintain docs again + +2005-09-23 Thomas Vander Stichele + + * Makefile.am: + * gtk-doc-plugins.mak: + * scangobj-merge.py: + merge additions from the .signals.new and .args.new file in + the original ones, only updating if necessary + +2005-09-23 Thomas Vander Stichele + + * gst-xmlinspect.py: + * gstdoc-scangobj: + * gtk-doc-plugins.mak: + fix properly for new API; make update in plugins dir now works + +2005-09-20 Thomas Vander Stichele + + * gst-xmlinspect.py: + * gstdoc-scangobj: + some fixes for new API + * gtk-doc-plugins.mak: + set environment properly + +2005-09-17 David Schleef + + * gtk-doc-plugins.mak: Use new environment variables. + +2005-09-16 Michael Smith + + * gstdoc-scangobj: + Make the scanobj code reflect registry/plugin API changes + +2005-09-15 Thomas Vander Stichele + + * gtk-doc-plugins.mak: + split out scanobj step (which will be run by doc maintainer) + from scan step (which will be run on every build) + clean up some of the commands for make distcheck + +2005-09-15 Thomas Vander Stichele + + * gtk-doc-plugins.mak: + * mangle-tmpl.py: + first stab at reorganizing the plugins build so we can maintain + element docs + +2005-09-14 David Schleef + + * as-libtool.mak: Remove + * m4/as-libtool.m4: The libtool bug that this worked around has + been fixed. + * m4/as-version.m4: Don't define GST_RELEASE, since it causes + config.h to be regenerated needlessly, and we don't use it. + +2005-09-14 Thomas Vander Stichele + + * gtk-doc-plugins.mak: + error out on inspect failure + +2005-09-14 Michael Smith + + * glib-gen.mak: + Don't call glib-mkenums with arguments that confuse/break MinGW, + fixes 316155. + +2005-09-03 Thomas Vander Stichele + + * gtk-doc-plugins.mak: + * gtk-doc.mak: + * m4/gst-doc.m4: + separate out gtk-doc and docbook stuff + have two separate --enable configure flags + +2005-08-26 Thomas Vander Stichele + + * check.mak: + add a .gdb target; rebuild registry for each target, otherwise + a code rebuild always triggers a reg rebuild, and it's just too + annoying + * gstdoc-scangobj: + +2005-08-21 Thomas Vander Stichele + + * check.mak: + separate out REGISTRY_ENVIRONMENT; we want to use that from + our valgrind runs, but we also want TESTS_ENVIRONMENT to contain + everything that the first test, gst-register, needs + +2005-08-21 Thomas Vander Stichele + + * check.mak: + parse output of valgrind and check for definitely lost, and error + out; somehow I was led to believe valgrind returns non-zero for + leaks, but I can't make it do that, so let's parse + +2005-08-20 Thomas Vander Stichele + + * check.mak: + for some weird reason valgrind does not report actual memleaks + if GST_PLUGIN_PATH is set to anything but the core gstreamer dir + while valgrind is running. Since the registry is going to go + anyway, I don't want to waste any more time on this; I just run + valgrind without GST_PLUGIN_PATH set. Since the registry loading + doesn't check if GST_PLUGIN_PATH got changed as a reason to rebuild + the registry, that's actually fine. + +2005-08-15 Thomas Vander Stichele + + * mangle-tmpl.py: + keep original Long_Description; only insert an include if it's + not already the first line in there + * plugins.xsl: + output more information for plugins, including an origin hyperlink + +2005-08-15 Thomas Vander Stichele + + * gst-xmlinspect.py: + a first stab at inspecting plugins and outputting an xml description + * gtk-doc-plugins.mak: + a gtk-doc using snippet for plugins documentation + * plugins.xsl: + a stylesheet to convert gst-xmlinspect.py output to docbook output + for inclusion in the gtk-doc stuff + +2005-07-20 Ronald S. Bultje + + * m4/gst-doc.m4: + s/pdf/eps/ in test for whether we output EPS images (#309379). + +2005-07-18 Andy Wingo + + * m4/as-libtool-tags.m4: Ooh, backported from libtool 1.6. Much + better. Thanks, Paolo Bonzini! + + * m4/Makefile.am (EXTRA_DIST): + * m4/as-libtool-tags.m4: New file, tries to disable some CXX and + fortran checks. + +2005-07-08 Thomas Vander Stichele + + * m4/gst-error.m4: + add macro to set ERROR_CFLAGS + +2005-06-30 Jan Schmidt + + * gst-autogen.sh: + Remove the old autoregen.sh if it exists before recreating it, + to prevent confusing any shell process that might be reading it + currently. + +2005-06-29 Thomas Vander Stichele + + * m4/gtk-doc.m4: + added + +2005-06-03 Stefan Kost + + * gst-autogen.sh: create autoregen.sh *before* shifting the options + +2005-05-17 Thomas Vander Stichele + + * gst-autogen.sh: only update autoregen.sh on actual runs + +2005-03-11 Thomas Vander Stichele + + * m4/check.m4: m4 from the check unit test suite + +2004-12-14 David Schleef + + * m4/gst-arch.m4: remove MMX stuff, since it doesn't work and + isn't needed anywhere + +2004-12-08 Thomas Vander Stichele + + * gst-autogen.sh: + allow failure command to be run so we can clean upfrom autopoint + +2004-09-03 Zeeshan Ali Khattak + * m4/gst-feature.m4: Trying to correct the GST_CHECK_CONFIGPROG macro + +2004-07-21 Benjamin Otte + + * m4/.cvsignore: exciting updates for libtool m4 files + +2004-07-12 David Schleef + + * m4/as-objc.m4: Add a macro to test for objective C + +2004-06-12 Thomas Vander Stichele + + * m4/gst-feature.m4: + not all of them support --plugin-libs, so redirect stderr + +2004-06-12 Thomas Vander Stichele + + * m4/as-scrub-include.m4: + sync with upstream to 0.1.4. Fixes #132440 + +2004-06-07 Benjamin Otte + + * m4/gst-feature.m4: + write a big marker into configure output when checking next plugin + to allow easier parsing of why plugins are(n't) built. + +2004-06-01 Thomas Vander Stichele + + * m4/as-compiler-flag.m4: + * m4/as-compiler.m4: + * m4/as-libtool.m4: + * m4/as-version.m4: + sync with upstream, change sticky options to -ko + +2004-05-24 Thomas Vander Stichele + + * m4/as-scrub-include.m4: synced with upstream + +2004-05-03 Thomas Vander Stichele + + * po.mak: + snippet for updating .po files + +2004-03-18 Thomas Vander Stichele + + * Makefile.am: + * m4/Makefile.am: + integrate these with the dist + +2004-03-17 Thomas Vander Stichele + + * release.mak: add a release target + +2004-03-09 Thomas Vander Stichele + + patch by: Stephane Loeuillet + + * m4/ax_create_stdint_h.m4: + use head -n instead of head - (#136500) + +2004-03-05 Thomas Vander Stichele + + * m4/gst-doc.m4: don't build PS without dvips binary + +2004-02-22 Julio M. Merino Vidal + + reviewed by: Benjamin Otte + + * m4/as-docbook.m4: + don't use == operator with test(1) (fixes #135115) + +2004-02-16 Thomas Vander Stichele + + * common/m4/gst-arch.m4: x86_64 is x86 too (clue from Fedora 2 test) + +2004-02-13 Thomas Vander Stichele + + * m4/gst-feature.m4: + remove AM_CONDITIONAL for the subsystem since automake 1.6.x + requires that call be in configure.ac + +2004-02-13 Thomas Vander Stichele + + * m4/gst-libxml2.m4: + take required version as argument, and default to 2.4.9 if not + specified + +2004-02-12 Thomas Vander Stichele + + * m4/gst-feature.m4: + rename and fix up GST_CHECK_DISABLE_SUBSYSTEM + +2004-02-11 Thomas Vander Stichele + + * common/m4/as-ac-expand.m4: + * common/m4/as-auto-alt.m4: + * common/m4/as-compiler-flag.m4: + * common/m4/as-compiler.m4: + * common/m4/as-docbook.m4: + * common/m4/as-libtool.m4: + * common/m4/as-scrub-include.m4: + * common/m4/as-version.m4: + * common/m4/glib-gettext.m4: + * common/m4/gst-arch.m4: + * common/m4/gst-debuginfo.m4: + * common/m4/gst-doc.m4: + * common/m4/gst-feature.m4: + * common/m4/gst-function.m4: + * common/m4/gst-glib2.m4: + * common/m4/gst-gstreamer.m4: + * common/m4/gst-libxml2.m4: + * common/m4/gst-makecontext.m4: + * common/m4/gst-mcsc.m4: + * common/m4/pkg.m4: + fix underquoted macros as reported by automake 1.8.x (#133800) + +2004-02-11 Johan Dahlin + + * gst-autogen.sh: Use A-Z instead of A-z in sed expression to + avoid a warning + +2004-02-05 Thomas Vander Stichele + + * m4/gst-doc.m4: + we use --output-format=xml and --ingnore-files options to + gtkdoc-mkdb, which got added between 0.9 and 1.0 + +2004-02-04 Thomas Vander Stichele + + * m4/as-libtool.m4: remove AM_PROG_LIBTOOL so it can move back + to configure.ac to shut up libtoolize + +2004-02-03 Thomas Vander Stichele + + * glib-gen.mak: added; used to generate enums and marshal code + +2004-01-13 Thomas Vander Stichele + + * gettext.patch: added; used by autogen.sh to make sure + GETTEXT_PACKAGE is understood from po/Makefile.in.in -> po/Makefile.in + diff --git a/common/Makefile.am b/common/Makefile.am new file mode 100644 index 0000000..cac4ff5 --- /dev/null +++ b/common/Makefile.am @@ -0,0 +1,16 @@ +SUBDIRS = m4 + +EXTRA_DIST = \ + ChangeLog \ + gettext.patch \ + glib-gen.mak gtk-doc.mak upload.mak release.mak win32.mak \ + gst-autogen.sh \ + check-exports \ + c-to-xml.py gst-xmlinspect.py mangle-tmpl.py scangobj-merge.py \ + gtk-doc-plugins.mak \ + plugins.xsl gstdoc-scangobj \ + gst.supp check.mak \ + coverage/lcov.mak \ + coverage/coverage-report.pl \ + coverage/coverage-report.xsl \ + coverage/coverage-report-entry.pl diff --git a/common/c-to-xml.py b/common/c-to-xml.py new file mode 100755 index 0000000..8448fd2 --- /dev/null +++ b/common/c-to-xml.py @@ -0,0 +1,34 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +""" +Convert a C program to valid XML to be included in docbook +""" + +import sys +import os +from xml.sax import saxutils + +def main(): + if len(sys.argv) == 1: + sys.stderr.write("Please specify a source file to convert") + sys.exit(1) + source = sys.argv[1] + + if not os.path.exists(source): + sys.stderr.write("%s does not exist.\n" % source) + sys.exit(1) + + content = open(source, "r").read() + + # print header + print '' + print '' + print + print '' + + # print content + print saxutils.escape(content).encode('UTF-8') + print '' + +main() diff --git a/common/check-exports b/common/check-exports new file mode 100755 index 0000000..16df41f --- /dev/null +++ b/common/check-exports @@ -0,0 +1,71 @@ +#!/bin/sh +# check-exports +# +# quick'n'dirty script that retrieves the list of exported symbols of a given +# library using 'nm', and compares that against the list of symbols-to-export +# of our win32/common/libfoo.def files. + +if [ $# -ne 2 ]; then + echo "Usage: $0 library.def library.so" + exit 1 +fi + +def_path="$1" +def_name="$(basename $def_path)" +lib_path="$2" + +lib_result="`mktemp /tmp/defname.XXXXXX`" + +LC_ALL=C +export LC_ALL + +# On Solaris, add -p to get the correct output format +NMARGS= +if nm -V 2>&1 |grep Solaris > /dev/null; then + NMARGS=-p +fi + +# FIXME 0.11: in 0.11, we should change the export filter to only export +# _gst_foo, but not __gst_foo (we can't change this now, since we added +# __gst_debug_min and __gst_debug_enabled at some point and need to keep +# ABI compatibility). So below we special-case some symbols that shouldn't +# really be exported, either because we're too lazy to rename them to something +# that's not exported (like the _gst_parse_* stuff) or because we had them in +# public headers at some point although they shouldn't be and so we need to +# keep them exported now (like _gst_debug_init, +# __gst_element_factory_add_interface or +# __gst_element_factory_add_static_pad_template). We suppress them here to +# make sure they're at least not exported in the windows msvc build (they +# were never in the .def file, so they never got exported). +# _end is special cased because for some reason it is reported as an exported +# BSS symbol, unlike on linux where it's a local absolute symbol. +nm $NMARGS $lib_path | awk \ + '{ + if ($3 !~ /^_gst_parse_yy/ && \ + $3 !~ /^_gst_[a-z]*_init/ && \ + $3 !~ /^_gst_parse_launch/ && \ + $3 !~ /^__gst_element_details_/ && \ + $3 !~ /^__gst_element_factory_add_/ && \ + $3 !~ /^gst_interfaces_marshal/ && \ + $3 ~ /^[_]*(gst_|Gst|GST_).*/) + { + if ($2 ~ /^[BSDG]$/) + print "\t" $3 " DATA" + else if ($2 == "T") + print "\t" $3 + } + }' | sort | awk '{ if (NR == 1) print "EXPORTS"; print $0; }' \ + > $lib_result + +diffoutput=`diff -u $def_path $lib_result` + +rm $lib_result + +if test "x$diffoutput" = "x"; then + exit 0; +else + echo -n "$diffoutput" >&2 + echo >&2 + exit 1; +fi + diff --git a/common/check.mak b/common/check.mak new file mode 100755 index 0000000..d31569f --- /dev/null +++ b/common/check.mak @@ -0,0 +1,149 @@ +clean-local-check: + for i in `find . -name ".libs" -type d`; do \ + rm -rf $$i; \ + done + +if HAVE_VALGRIND +# hangs spectacularly on some machines, so let's not do this by default yet +check-valgrind: + $(MAKE) valgrind +else +check-valgrind: + @true +endif + +LOOPS = 10 + +# run any given test by running make test.check +# if the test fails, run it again at at least debug level 2 +%.check: % + @$(TESTS_ENVIRONMENT) \ + CK_DEFAULT_TIMEOUT=20 \ + $* || \ + $(TESTS_ENVIRONMENT) \ + GST_DEBUG=$$GST_DEBUG,*:2 \ + CK_DEFAULT_TIMEOUT=20 \ + $* + +# run any given test in a loop +%.torture: % + @for i in `seq 1 $(LOOPS)`; do \ + $(TESTS_ENVIRONMENT) \ + CK_DEFAULT_TIMEOUT=20 \ + $*; done + +# run any given test in an infinite loop +%.forever: % + @while true; do \ + $(TESTS_ENVIRONMENT) \ + CK_DEFAULT_TIMEOUT=20 \ + $* || break; done + +# valgrind any given test by running make test.valgrind +%.valgrind: % + $(TESTS_ENVIRONMENT) \ + CK_DEFAULT_TIMEOUT=360 \ + G_SLICE=always-malloc \ + libtool --mode=execute \ + $(VALGRIND_PATH) -q \ + $(foreach s,$(SUPPRESSIONS),--suppressions=$(s)) \ + --tool=memcheck --leak-check=full --trace-children=yes \ + --leak-resolution=high --num-callers=20 \ + ./$* 2>&1 | tee valgrind.log + @if grep "==" valgrind.log > /dev/null 2>&1; then \ + rm valgrind.log; \ + exit 1; \ + fi + @rm valgrind.log + +# valgrind any given test and generate suppressions for it +%.valgrind.gen-suppressions: % + $(TESTS_ENVIRONMENT) \ + CK_DEFAULT_TIMEOUT=360 \ + G_SLICE=always-malloc \ + libtool --mode=execute \ + $(VALGRIND_PATH) -q \ + $(foreach s,$(SUPPRESSIONS),--suppressions=$(s)) \ + --tool=memcheck --leak-check=full --trace-children=yes \ + --leak-resolution=high --num-callers=20 \ + --gen-suppressions=all \ + ./$* 2>&1 | tee suppressions.log + +# valgrind any given test until failure by running make test.valgrind-forever +%.valgrind-forever: % + @while $(MAKE) $*.valgrind; do \ + true; done + +# gdb any given test by running make test.gdb +%.gdb: % + $(TESTS_ENVIRONMENT) \ + CK_FORK=no \ + libtool --mode=execute \ + gdb $* + +# torture tests +torture: $(TESTS) + -rm test-registry.xml + @echo "Torturing tests ..." + for i in `seq 1 $(LOOPS)`; do \ + $(MAKE) check || \ + (echo "Failure after $$i runs"; exit 1) || \ + exit 1; \ + done + @banner="All $(LOOPS) loops passed"; \ + dashes=`echo "$$banner" | sed s/./=/g`; \ + echo $$dashes; echo $$banner; echo $$dashes + +# forever tests +forever: $(TESTS) + -rm test-registry.xml + @echo "Forever tests ..." + while true; do \ + $(MAKE) check || \ + (echo "Failure"; exit 1) || \ + exit 1; \ + done + +# valgrind all tests +valgrind: $(TESTS) + @echo "Valgrinding tests ..." + @failed=0; \ + for t in $(filter-out $(VALGRIND_TESTS_DISABLE),$(TESTS)); do \ + $(MAKE) $$t.valgrind; \ + if test "$$?" -ne 0; then \ + echo "Valgrind error for test $$t"; \ + failed=`expr $$failed + 1`; \ + whicht="$$whicht $$t"; \ + fi; \ + done; \ + if test "$$failed" -ne 0; then \ + echo "$$failed tests had leaks or errors under valgrind:"; \ + echo "$$whicht"; \ + false; \ + fi + +# inspect every plugin feature +GST_INSPECT = $(GST_TOOLS_DIR)/gst-inspect-$(GST_MAJORMINOR) +inspect: + @echo "Inspecting features ..." + for e in `$(TESTS_ENVIRONMENT) $(GST_INSPECT) | head -n -2 \ + | cut -d: -f2`; \ + do echo Inspecting $$e; \ + $(GST_INSPECT) $$e > /dev/null 2>&1; done + +help: + @echo "make check -- run all checks" + @echo "make torture -- run all checks $(LOOPS) times" + @echo "make (dir)/(test).check -- run the given check once" + @echo "make (dir)/(test).forever -- run the given check forever" + @echo "make (dir)/(test).torture -- run the given check $(LOOPS) times" + @echo + @echo "make (dir)/(test).gdb -- start up gdb for the given test" + @echo + @echo "make valgrind -- valgrind all tests" + @echo "make (dir)/(test).valgrind -- valgrind the given test" + @echo "make (dir)/(test).valgrind-forever -- valgrind the given test forever" + @echo "make (dir)/(test).valgrind.gen-suppressions -- generate suppressions" + @echo " and save to suppressions.log" + @echo "make inspect -- inspect all plugin features" + diff --git a/common/coverage/coverage-report-entry.pl b/common/coverage/coverage-report-entry.pl new file mode 100755 index 0000000..8f653af --- /dev/null +++ b/common/coverage/coverage-report-entry.pl @@ -0,0 +1,70 @@ +#!/usr/bin/perl +# +# Copyright (C) 2006 Daniel Berrange +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +print < + +Coverage report for $ARGV[0] + + + +

Coverage report for $ARGV[0]

+ +
+EOF
+
+
+while (<>) {
+    s/&/&/g;
+    s//>/g;
+
+    if (/^\s*function (\S+) called (\d+) returned \d+% blocks executed \d+%/) {
+	my $class = $2 > 0 ? "perfect" : "terrible";
+	$_ = "$_";
+    } elsif (/^\s*branch\s+\d+\s+taken\s+(\d+)%\s+.*$/) {
+	my $class = $1 > 0 ? "perfect" : "terrible";
+	$_ = "$_";
+    } elsif (/^\s*branch\s+\d+\s+never executed.*$/) {
+	my $class = "terrible";
+	$_ = "$_";
+    } elsif (/^\s*call\s+\d+\s+never executed.*$/) {
+	my $class = "terrible";
+	$_ = "$_";
+    } elsif (/^\s*call\s+\d+\s+returned\s+(\d+)%.*$/) {
+	my $class = $1 > 0 ? "perfect" : "terrible";
+	$_ = "$_";
+    }
+    
+
+    print;
+}
+
+print <
+
+
+EOF
diff --git a/common/coverage/coverage-report.pl b/common/coverage/coverage-report.pl
new file mode 100755
index 0000000..046bc37
--- /dev/null
+++ b/common/coverage/coverage-report.pl
@@ -0,0 +1,125 @@
+#!/usr/bin/perl
+#
+# Copyright (C) 2006 Daniel Berrange
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+use warnings;
+use strict;
+
+my %coverage = ( functions => {}, files => {} );
+
+my %filemap;
+
+my $type;
+my $name;
+
+my @functions;
+
+while (<>) {
+    if (/^Function '(.*)'\s*$/) {
+	$type = "function";
+	$name = $1;
+	$coverage{$type}->{$name} = {};
+	push @functions, $name;
+    } elsif (/^File '(.*?)'\s*$/) {
+	$type = "file";
+	$name = $1;
+	$coverage{$type}->{$name} = {};
+	
+	foreach my $func (@functions) {
+	    $coverage{"function"}->{$func}->{file} = $name;
+	}
+	@functions = ();
+    } elsif (/^Lines executed:(.*)%\s*of\s*(\d+)\s*$/) {
+	$coverage{$type}->{$name}->{lines} = $2;
+	$coverage{$type}->{$name}->{linesCoverage} = $1;
+    } elsif (/^Branches executed:(.*)%\s*of\s*(\d+)\s*$/) {
+	$coverage{$type}->{$name}->{branches} = $2;
+	$coverage{$type}->{$name}->{branchesCoverage} = $1;
+    } elsif (/^Taken at least once:(.*)%\s*of\s*(\d+)\s*$/) {
+	$coverage{$type}->{$name}->{conds} = $2;
+	$coverage{$type}->{$name}->{condsCoverage} = $1;
+    } elsif (/^Calls executed:(.*)%\s*of\s*(\d+)\s*$/) {
+	$coverage{$type}->{$name}->{calls} = $2;
+	$coverage{$type}->{$name}->{callsCoverage} = $1;
+    } elsif (/^No branches$/) {
+	$coverage{$type}->{$name}->{branches} = 0;
+	$coverage{$type}->{$name}->{branchesCoverage} = "100.00";
+	$coverage{$type}->{$name}->{conds} = 0;
+	$coverage{$type}->{$name}->{condsCoverage} = "100.00";
+    } elsif (/^No calls$/) {
+	$coverage{$type}->{$name}->{calls} = 0;
+	$coverage{$type}->{$name}->{callsCoverage} = "100.00";
+    } elsif (/^\s*(.*):creating '(.*)'\s*$/) {
+	$filemap{$1} = $2;
+    } elsif (/^\s*$/) {
+	# nada
+    } else {
+	warn "Shit [$_]\n";
+    }
+}
+
+my %summary;
+foreach my $type ("function", "file") {
+    $summary{$type} = {};
+    foreach my $m ("lines", "branches", "conds", "calls") {
+	my $totalGot = 0;
+	my $totalMiss = 0;
+	my $count = 0;
+	foreach my $func (keys %{$coverage{function}}) {
+	    $count++;
+	    my $got = $coverage{function}->{$func}->{$m};
+	    $totalGot += $got;
+	    my $miss = $got * $coverage{function}->{$func}->{$m ."Coverage"} / 100;
+	    $totalMiss += $miss;
+	}
+	$summary{$type}->{$m} = sprintf("%d", $totalGot);
+	$summary{$type}->{$m . "Coverage"} = sprintf("%.2f", $totalMiss / $totalGot * 100);
+    }
+}
+
+
+
+print "\n";
+
+foreach my $type ("function", "file") {
+    printf "<%ss>\n", $type;
+    foreach my $name (sort { $a cmp $b } keys %{$coverage{$type}}) {
+	my $rec = $coverage{$type}->{$name};
+	printf "  \n", $name, ($type eq "file" ? $filemap{$name} : $filemap{$rec->{file}});
+	printf "    \n", $rec->{lines}, $rec->{linesCoverage};
+	if (exists $rec->{branches}) {
+	    printf "    \n", $rec->{branches}, $rec->{branchesCoverage};
+	}
+	if (exists $rec->{conds}) {
+	    printf "    \n", $rec->{conds}, $rec->{condsCoverage};
+	}
+	if (exists $rec->{calls}) {
+	    printf "    \n", $rec->{calls}, $rec->{callsCoverage};
+	}
+	print  "  \n";
+    }
+    
+    printf "  \n";
+    printf "    \n", $summary{$type}->{lines}, $summary{$type}->{linesCoverage};
+    printf "    \n", $summary{$type}->{branches}, $summary{$type}->{branchesCoverage};
+    printf "    \n", $summary{$type}->{conds}, $summary{$type}->{condsCoverage};
+    printf "    \n", $summary{$type}->{calls}, $summary{$type}->{callsCoverage};
+    printf  "  \n";
+    printf "\n", $type;
+}
+
+print "\n";
diff --git a/common/coverage/coverage-report.xsl b/common/coverage/coverage-report.xsl
new file mode 100755
index 0000000..b19ebb6
--- /dev/null
+++ b/common/coverage/coverage-report.xsl
@@ -0,0 +1,235 @@
+
+
+
+
+  
+
+  
+    
+      
+        Coverage report
+        
+      
+      
+        

Coverage report

+ + + +
+ + +

Function coverage

+ + + +
+ + + +

File coverage

+ + + +
+ + + + + + + + + + + + + + + + + + + + + odd + + + even + + + + + + + + + + + + + + odd + + + even + + + + + + +
NameLinesBranchesConditionsCalls
+
+ + + + + + + + + + + + + + Summary + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + perfect + + + excellant + + + good + + + poor + + + bad + + + terrible + + + + + % of + + +
diff --git a/common/coverage/lcov.mak b/common/coverage/lcov.mak new file mode 100755 index 0000000..0ca9456 --- /dev/null +++ b/common/coverage/lcov.mak @@ -0,0 +1,42 @@ +## .PHONY so it always rebuilds it +.PHONY: lcov-reset lcov lcov-run lcov-report lcov-upload + +# run lcov from scratch, always +lcov-reset: + $(MAKE) lcov-run + $(MAKE) lcov-report + +# run lcov from scratch if the dir is not there +lcov: + $(MAKE) lcov-reset + +if GST_GCOV_ENABLED +# reset run coverage tests +lcov-run: + @-rm -rf lcov + lcov --directory . --zerocounters + -if test -d tests/check; then $(MAKE) -C tests/check inspect; fi + -$(MAKE) check + +# generate report based on current coverage data +lcov-report: + mkdir lcov + lcov --compat-libtool --directory . --capture --output-file lcov/lcov.info + lcov -l lcov/lcov.info | grep -v "`cd $(top_srcdir) && pwd`" | cut -d: -f1 > lcov/remove + lcov -l lcov/lcov.info | grep "tests/check/" | cut -d: -f1 >> lcov/remove + lcov -r lcov/lcov.info `cat lcov/remove` > lcov/lcov.cleaned.info + rm lcov/remove + mv lcov/lcov.cleaned.info lcov/lcov.info + genhtml -t "$(PACKAGE_STRING)" -o lcov --num-spaces 2 lcov/lcov.info + +lcov-upload: lcov + rsync -rvz -e ssh --delete lcov/* gstreamer.freedesktop.org:/srv/gstreamer.freedesktop.org/www/data/coverage/lcov/$(PACKAGE) + +else +lcov-run: + echo "Need to reconfigure with --enable-gcov" + +lcov-report: + echo "Need to reconfigure with --enable-gcov" +endif + diff --git a/common/gettext.patch b/common/gettext.patch new file mode 100755 index 0000000..659718e --- /dev/null +++ b/common/gettext.patch @@ -0,0 +1,23 @@ +--- po/Makefile.in.in.orig 2006-01-07 12:03:45.000000000 +0100 ++++ po/Makefile.in.in 2006-01-07 12:04:23.000000000 +0100 +@@ -11,6 +11,9 @@ + PACKAGE = @PACKAGE@ + VERSION = @VERSION@ + ++# thomas: add GETTEXT_PACKAGE substitution as used in Makevars ++GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ ++ + SHELL = /bin/sh + @SET_MAKE@ + +@@ -305,7 +308,9 @@ + update-gmo: Makefile $(GMOFILES) + @: + +-Makefile: Makefile.in.in $(top_builddir)/config.status POTFILES.in ++# thomas: add LINGUAS as a dependency so that the Makefile gets rebuilt ++# properly when we add languages ++Makefile: Makefile.in.in $(top_builddir)/config.status POTFILES.in LINGUAS + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@.in CONFIG_HEADERS= \ + $(SHELL) ./config.status diff --git a/common/glib-gen.mak b/common/glib-gen.mak new file mode 100755 index 0000000..f9027da --- /dev/null +++ b/common/glib-gen.mak @@ -0,0 +1,44 @@ +# these are the variables your Makefile.am should set +# the example is based on the colorbalance interface + +#glib_enum_headers=$(colorbalance_headers) +#glib_enum_define=GST_COLOR_BALANCE +#glib_enum_prefix=gst_color_balance + +enum_headers=$(foreach h,$(glib_enum_headers),\n\#include \"$(h)\") + +# these are all the rules generating the relevant files +%-marshal.h: %-marshal.list + glib-genmarshal --header --prefix=$(glib_enum_prefix)_marshal $^ > $*-marshal.h.tmp + mv $*-marshal.h.tmp $*-marshal.h + +%-marshal.c: %-marshal.list + echo "#include \"$*-marshal.h\"" >> $*-marshal.c.tmp + glib-genmarshal --body --prefix=$(glib_enum_prefix)_marshal $^ >> $*-marshal.c.tmp + mv $*-marshal.c.tmp $*-marshal.c + +%-enumtypes.h: $(glib_enum_headers) + glib-mkenums \ + --fhead "#ifndef __$(glib_enum_define)_ENUM_TYPES_H__\n#define __$(glib_enum_define)_ENUM_TYPES_H__\n\n#include \n\nG_BEGIN_DECLS\n" \ + --fprod "\n/* enumerations from \"@filename@\" */\n" \ + --vhead "GType @enum_name@_get_type (void);\n#define GST_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n" \ + --ftail "G_END_DECLS\n\n#endif /* __$(glib_enum_define)_ENUM_TYPES_H__ */" \ + $^ > $@ + +%-enumtypes.c: $(glib_enum_headers) + @if test "x$(glib_enum_headers)" == "x"; then echo "ERROR: glib_enum_headers is empty, please fix Makefile"; exit 1; fi + glib-mkenums \ + --fhead "#include \"$*-enumtypes.h\"\n$(enum_headers)" \ + --fprod "\n/* enumerations from \"@filename@\" */" \ + --vhead "GType\n@enum_name@_get_type (void)\n{\n static GType etype = 0;\n if (etype == 0) {\n static const G@Type@Value values[] = {" \ + --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \ + --vtail " { 0, NULL, NULL }\n };\n etype = g_@type@_register_static (\"@EnumName@\", values);\n }\n return etype;\n}\n" \ + $^ > $@ + +# a hack rule to make sure .Plo files exist because they get include'd +# from Makefile's +.deps/%-marshal.Plo: + touch $@ + +.deps/%-enumtypes.Plo: + touch $@ diff --git a/common/gst-autogen.sh b/common/gst-autogen.sh new file mode 100755 index 0000000..ae60f7e --- /dev/null +++ b/common/gst-autogen.sh @@ -0,0 +1,294 @@ +# a silly hack that generates autoregen.sh but it's handy +# Remove the old autoregen.sh first to create a new file, +# as the current one may be being read by the shell executing +# this script. +if [ -f "autoregen.sh" ]; then + rm autoregen.sh +fi +echo "#!/bin/sh" > autoregen.sh +echo "./autogen.sh $@ \$@" >> autoregen.sh +chmod +x autoregen.sh + +# helper functions for autogen.sh + +debug () +# print out a debug message if DEBUG is a defined variable +{ + if test ! -z "$DEBUG" + then + echo "DEBUG: $1" + fi +} + +version_check () +# check the version of a package +# first argument : package name (executable) +# second argument : optional path where to look for it instead +# third argument : source download url +# rest of arguments : major, minor, micro version +# all consecutive ones : suggestions for binaries to use +# (if not specified in second argument) +{ + PACKAGE=$1 + PKG_PATH=$2 + URL=$3 + MAJOR=$4 + MINOR=$5 + MICRO=$6 + + # for backwards compatibility, we let PKG_PATH=PACKAGE when PKG_PATH null + if test -z "$PKG_PATH"; then PKG_PATH=$PACKAGE; fi + debug "major $MAJOR minor $MINOR micro $MICRO" + VERSION=$MAJOR + if test ! -z "$MINOR"; then VERSION=$VERSION.$MINOR; else MINOR=0; fi + if test ! -z "$MICRO"; then VERSION=$VERSION.$MICRO; else MICRO=0; fi + + debug "major $MAJOR minor $MINOR micro $MICRO" + + for SUGGESTION in $PKG_PATH; do + COMMAND="$SUGGESTION" + + # don't check if asked not to + test -z "$NOCHECK" && { + echo -n " checking for $COMMAND >= $VERSION ... " + } || { + # we set a var with the same name as the package, but stripped of + # unwanted chars + VAR=`echo $PACKAGE | sed 's/-//g'` + debug "setting $VAR" + eval $VAR="$COMMAND" + return 0 + } + + debug "checking version with $COMMAND" + ($COMMAND --version) < /dev/null > /dev/null 2>&1 || + { + echo "not found." + continue + } + # strip everything that's not a digit, then use cut to get the first field + pkg_version=`$COMMAND --version|head -n 1|sed 's/^.*)[^0-9]*//'|cut -d' ' -f1` + debug "pkg_version $pkg_version" + # remove any non-digit characters from the version numbers to permit numeric + # comparison + pkg_major=`echo $pkg_version | cut -d. -f1 | sed s/[a-zA-Z\-].*//g` + pkg_minor=`echo $pkg_version | cut -d. -f2 | sed s/[a-zA-Z\-].*//g` + pkg_micro=`echo $pkg_version | cut -d. -f3 | sed s/[a-zA-Z\-].*//g` + test -z "$pkg_major" && pkg_major=0 + test -z "$pkg_minor" && pkg_minor=0 + test -z "$pkg_micro" && pkg_micro=0 + debug "found major $pkg_major minor $pkg_minor micro $pkg_micro" + + #start checking the version + debug "version check" + + # reset check + WRONG= + + if [ ! "$pkg_major" -gt "$MAJOR" ]; then + debug "major: $pkg_major <= $MAJOR" + if [ "$pkg_major" -lt "$MAJOR" ]; then + debug "major: $pkg_major < $MAJOR" + WRONG=1 + elif [ ! "$pkg_minor" -gt "$MINOR" ]; then + debug "minor: $pkg_minor <= $MINOR" + if [ "$pkg_minor" -lt "$MINOR" ]; then + debug "minor: $pkg_minor < $MINOR" + WRONG=1 + elif [ "$pkg_micro" -lt "$MICRO" ]; then + debug "micro: $pkg_micro < $MICRO" + WRONG=1 + fi + fi + fi + + if test ! -z "$WRONG"; then + echo "found $pkg_version, not ok !" + continue + else + echo "found $pkg_version, ok." + # we set a var with the same name as the package, but stripped of + # unwanted chars + VAR=`echo $PACKAGE | sed 's/-//g'` + debug "setting $VAR" + eval $VAR="$COMMAND" + return 0 + fi + done + + echo "not found !" + echo "You must have $PACKAGE installed to compile $package." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at $URL" + return 1; +} + +aclocal_check () +{ + # normally aclocal is part of automake + # so we expect it to be in the same place as automake + # so if a different automake is supplied, we need to adapt as well + # so how's about replacing automake with aclocal in the set var, + # and saving that in $aclocal ? + # note, this will fail if the actual automake isn't called automake* + # or if part of the path before it contains it + if [ -z "$automake" ]; then + echo "Error: no automake variable set !" + return 1 + else + aclocal=`echo $automake | sed s/automake/aclocal/` + debug "aclocal: $aclocal" + if [ "$aclocal" != "aclocal" ]; + then + CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-aclocal=$aclocal" + fi + if [ ! -x `which $aclocal` ]; then + echo "Error: cannot execute $aclocal !" + return 1 + fi + fi +} + +autoheader_check () +{ + # same here - autoheader is part of autoconf + # use the same voodoo + if [ -z "$autoconf" ]; then + echo "Error: no autoconf variable set !" + return 1 + else + autoheader=`echo $autoconf | sed s/autoconf/autoheader/` + debug "autoheader: $autoheader" + if [ "$autoheader" != "autoheader" ]; + then + CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-autoheader=$autoheader" + fi + if [ ! -x `which $autoheader` ]; then + echo "Error: cannot execute $autoheader !" + return 1 + fi + fi + +} +autoconf_2_52d_check () +{ + # autoconf 2.52d has a weird issue involving a yes:no error + # so don't allow it's use + test -z "$NOCHECK" && { + ac_version=`$autoconf --version|head -n 1|sed 's/^[a-zA-Z\.\ ()]*//;s/ .*$//'` + if test "$ac_version" = "2.52d"; then + echo "autoconf 2.52d has an issue with our current build." + echo "We don't know who's to blame however. So until we do, get a" + echo "regular version. RPM's of a working version are on the gstreamer site." + exit 1 + fi + } + return 0 +} + +die_check () +{ + # call with $DIE + # if set to 1, we need to print something helpful then die + DIE=$1 + if test "x$DIE" = "x1"; + then + echo + echo "- Please get the right tools before proceeding." + echo "- Alternatively, if you're sure we're wrong, run with --nocheck." + exit 1 + fi +} + +autogen_options () +{ + if test "x$1" = "x"; then + return 0 + fi + + while test "x$1" != "x" ; do + optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + case "$1" in + --noconfigure) + NOCONFIGURE=defined + AUTOGEN_EXT_OPT="$AUTOGEN_EXT_OPT --noconfigure" + echo "+ configure run disabled" + shift + ;; + --nocheck) + AUTOGEN_EXT_OPT="$AUTOGEN_EXT_OPT --nocheck" + NOCHECK=defined + echo "+ autotools version check disabled" + shift + ;; + --debug) + DEBUG=defined + AUTOGEN_EXT_OPT="$AUTOGEN_EXT_OPT --debug" + echo "+ debug output enabled" + shift + ;; + -h|--help) + echo "autogen.sh (autogen options) -- (configure options)" + echo "autogen.sh help options: " + echo " --noconfigure don't run the configure script" + echo " --nocheck don't do version checks" + echo " --debug debug the autogen process" + echo + echo " --with-autoconf PATH use autoconf in PATH" + echo " --with-automake PATH use automake in PATH" + echo + echo "Any argument either not in the above list or after a '--' will be " + echo "passed to ./configure." + exit 1 + ;; + --with-automake=*) + AUTOMAKE=$optarg + echo "+ using alternate automake in $optarg" + CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-automake=$AUTOMAKE" + shift + ;; + --with-autoconf=*) + AUTOCONF=$optarg + echo "+ using alternate autoconf in $optarg" + CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-autoconf=$AUTOCONF" + shift + ;; + --) shift ; break ;; + *) + echo "+ passing argument $1 to configure" + CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT $1" + shift + ;; + esac + done + + for arg do CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT $arg"; done + if test ! -z "$CONFIGURE_EXT_OPT" + then + echo "+ options passed to configure: $CONFIGURE_EXT_OPT" + fi +} + +toplevel_check () +{ + srcfile=$1 + test -f $srcfile || { + echo "You must run this script in the top-level $package directory" + exit 1 + } +} + + +tool_run () +{ + tool=$1 + options=$2 + run_if_fail=$3 + echo "+ running $tool $options..." + $tool $options || { + echo + echo $tool failed + eval $run_if_fail + exit 1 + } +} diff --git a/common/gst-xmlinspect.py b/common/gst-xmlinspect.py new file mode 100755 index 0000000..4a1a5c7 --- /dev/null +++ b/common/gst-xmlinspect.py @@ -0,0 +1,168 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +""" +examine all plugins and elements and output xml documentation for them +used as part of the plugin documentation build +""" + +import sys +import os +import pygst +pygst.require('1.0') +import gst + +INDENT_SIZE = 2 + +# all templates + +PAD_TEMPLATE = """ + %(name)s + %(direction)s + %(presence)s +
%(details)s
+
""" + +ELEMENT_TEMPLATE = """ + %(name)s + %(longname)s + %(class)s + %(description)s + %(author)s + +%(pads)s + +""" + +PLUGIN_TEMPLATE = """ + %(name)s + %(description)s + %(filename)s + %(basename)s + %(version)s + %(license)s + %(source)s + %(package)s + %(origin)s + +%(elements)s + +""" + +def xmlencode(line): + """ + Replace &, <, and > + """ + line = "&".join(line.split("&")) + line = "<".join(line.split("<")) + line = ">".join(line.split(">")) + return line + +def get_offset(indent): + return " " * INDENT_SIZE * indent + +def output_pad_template(pt, indent=0): + print "PAD TEMPLATE", pt.name_template + paddir = ("unknown","source","sink") + padpres = ("always","sometimes","request") + + d = { + 'name': xmlencode(pt.name_template), + 'direction': xmlencode(paddir[pt.direction]), + 'presence': xmlencode(padpres[pt.presence]), + 'details': xmlencode(pt.static_caps.string), + } + block = PAD_TEMPLATE % d + + offset = get_offset(indent) + return offset + ("\n" + offset).join(block.split("\n")) + +def output_element_factory(elf, indent=0): + print "ELEMENT", elf.get_name() + + padsoutput = [] + padtemplates = elf.get_static_pad_templates() + for padtemplate in padtemplates: + padsoutput.append(output_pad_template(padtemplate, indent)) + + d = { + 'name': xmlencode(elf.get_name()), + 'longname': xmlencode(elf.get_longname()), + 'class': xmlencode(elf.get_klass()), + 'description': xmlencode(elf.get_description()), + 'author': xmlencode(elf.get_author()), + 'pads': "\n".join(padsoutput), + } + block = ELEMENT_TEMPLATE % d + + offset = get_offset(indent) + return offset + ("\n" + offset).join(block.split("\n")) + +def output_plugin(plugin, indent=0): + print "PLUGIN", plugin.get_name() + version = plugin.get_version() + + elements = {} + gst.debug('getting features for plugin %s' % plugin.get_name()) + registry = gst.registry_get_default() + features = registry.get_feature_list_by_plugin(plugin.get_name()) + gst.debug('plugin %s has %d features' % (plugin.get_name(), len(features))) + for feature in features: + if isinstance(feature, gst.ElementFactory): + elements[feature.get_name()] = feature + #gst.debug("got features") + + elementsoutput = [] + keys = elements.keys() + keys.sort() + for name in keys: + feature = elements[name] + elementsoutput.append(output_element_factory(feature, indent + 2)) + + filename = plugin.get_filename() + basename = filename + if basename: + basename = os.path.basename(basename) + d = { + 'name': xmlencode(plugin.get_name()), + 'description': xmlencode(plugin.get_description()), + 'filename': filename, + 'basename': basename, + 'version': version, + 'license': xmlencode(plugin.get_license()), + 'source': xmlencode(plugin.get_source()), + 'package': xmlencode(plugin.get_package()), + 'origin': xmlencode(plugin.get_origin()), + 'elements': "\n".join(elementsoutput), + } + block = PLUGIN_TEMPLATE % d + + offset = get_offset(indent) + return offset + ("\n" + offset).join(block.split("\n")) + +def main(): + if len(sys.argv) == 1: + sys.stderr.write("Please specify a source module to inspect") + sys.exit(1) + source = sys.argv[1] + + if len(sys.argv) > 2: + os.chdir(sys.argv[2]) + + registry = gst.registry_get_default() + all = registry.get_plugin_list() + for plugin in all: + gst.debug("inspecting plugin %s from source %s" % ( + plugin.get_name(), plugin.get_source())) + # this skips gstcoreelements, with bin and pipeline + if plugin.get_filename() is None: + continue + if plugin.get_source() != source: + continue + + filename = "plugin-%s.xml" % plugin.get_name() + handle = open(filename, "w") + handle.write(output_plugin(plugin)) + handle.close() + +main() diff --git a/common/gst.supp b/common/gst.supp new file mode 100755 index 0000000..9b2a3a2 --- /dev/null +++ b/common/gst.supp @@ -0,0 +1,1988 @@ +### this file contains suppressions for valgrind when running +### the gstreamer unit tests +### it might be useful for wider use as well + +### syscall suppressions + +{ + + Memcheck:Param + clone(parent_tidptr) + fun:clone + fun:clone +} + +{ + + Memcheck:Param + clone(child_tidptr) + fun:clone + fun:clone +} + +{ + + Memcheck:Param + clone(tlsinfo) + fun:clone + fun:clone +} + +### glibc suppressions + +{ + + Memcheck:Cond + obj:/lib/ld-2.3.*.so + fun:dl_open_worker + obj:/lib/ld-2.3.*.so + fun:_dl_open + fun:dlopen_doit + obj:/lib/ld-2.3.*.so + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open + fun:gst_plugin_load_file +} + +# glibc does not deallocate thread-local storage + +{ + + Memcheck:Leak + fun:calloc + fun:_dl_allocate_tls + fun:pthread_create@@* +} + +# I get an extra stack entry on x86/dapper +{ + + Memcheck:Leak + fun:calloc + obj:/lib/ld-2.3.*.so + fun:_dl_allocate_tls + fun:pthread_create@@* +} + + +{ + + Memcheck:Cond + fun:strstr + fun:__pthread_initialize_minimal + obj:/lib/libpthread-*.so + obj:/lib/libpthread-*.so + fun:call_init + fun:_dl_init + obj:/lib/ld-*.so +} + +# a thread-related free problem in glibc from Edgard +{ + __libc_freeres_rw_acess + Memcheck:Addr4 + obj:* + obj:* + obj:* + obj:* + obj:* + fun:__libc_freeres +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so +} + +# g_module_open-related problems +{ + + Memcheck:Addr2 + fun:memcpy + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open + fun:gst_plugin_load_file + fun:gst_registry_scan_path_level + fun:gst_registry_scan_path_level + fun:gst_registry_scan_path_level + fun:init_post + fun:g_option_context_parse + fun:gst_init_check + fun:gst_init + fun:gst_check_init + fun:main +} + +{ + + Memcheck:Addr4 + fun:memcpy + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open + fun:gst_plugin_load_file + fun:gst_registry_scan_path_level + fun:gst_registry_scan_path_level + fun:gst_registry_scan_path_level + fun:init_post + fun:g_option_context_parse + fun:gst_init_check + fun:gst_init + fun:gst_check_init + fun:main +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + fun:do_sym + fun:_dl_sym + fun:dlsym_doit + obj:/lib/ld-2.3.*.so + fun:_dlerror_run + fun:dlsym + fun:g_module_symbol + fun:g_module_open + fun:gst_plugin_load_file +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + fun:dl_open_worker + obj:/lib/ld-2.3.*.so + fun:_dl_open + fun:dlopen_doit + obj:/lib/ld-2.3.*.so + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open + fun:gst_plugin_load_file +} +{ + + Memcheck:Cond + obj:/lib/ld-2.3.*.so + fun:dl_open_worker + obj:/lib/ld-2.3.*.so + fun:_dl_open + fun:dlopen_doit + obj:/lib/ld-2.3.*.so + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open + fun:gst_plugin_load_file + fun:gst_plugin_load_by_name + fun:gst_plugin_feature_load +} + +{ + + Memcheck:Leak + fun:malloc + obj:/lib/ld-2.3.*.so + fun:dl_open_worker + obj:/lib/ld-2.3.*.so + fun:_dl_open + fun:dlopen_doit + obj:/lib/ld-2.3.*.so + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open + fun:gst_plugin_load_file + fun:gst_plugin_load_by_name +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + fun:dl_open_worker + obj:/lib/ld-2.3.*.so + fun:_dl_open + fun:dlopen_doit + obj:/lib/ld-2.3.*.so +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + fun:dl_open_worker + obj:/lib/ld-2.3.*.so + fun:_dl_open + fun:dlopen_doit + obj:/lib/ld-2.3.*.so + fun:_dlerror_run +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + fun:dl_open_worker + obj:/lib/ld-2.3.*.so + fun:_dl_open + fun:dlopen_doit + obj:/lib/ld-2.3.*.so + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + fun:dl_open_worker + obj:/lib/ld-2.3.*.so + fun:_dl_open + fun:dlopen_doit + obj:/lib/ld-2.3.*.so + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + fun:do_sym + fun:_dl_sym + fun:dlsym_doit + obj:/lib/ld-2.3.*.so + fun:_dlerror_run + fun:dlsym + fun:g_module_symbol + fun:g_module_open +} + +{ + + Memcheck:Param + futex(uaddr2) + fun:pthread_once + obj:/lib/libc-2.3.*.so + obj:/lib/libc-2.3.*.so + fun:mbsnrtowcs + fun:vfprintf + fun:vsprintf + fun:sprintf + obj:/lib/libc-2.3.*.so + fun:tmpfile + fun:setup_pipe + fun:setup_messaging_with_key + fun:setup_messaging +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + fun:dlopen + fun:g_module_open +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libc-2.7.so + fun:_dl_sym + obj:/lib/i686/cmov/libdl-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + fun:dlsym + fun:g_module_symbol + fun:g_module_open +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + fun:dlopen + fun:g_module_open +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + fun:dlopen + fun:g_module_open +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + fun:dlopen + fun:g_module_open +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libc-2.7.so + obj:/lib/ld-2.7.so + fun:__libc_dlopen_mode +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libc-2.7.so + obj:/lib/ld-2.7.so + fun:__libc_dlopen_mode +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libc-2.7.so + obj:/lib/ld-2.7.so + fun:__libc_dlopen_mode + obj:/lib/i686/cmov/libc-2.7.so + obj:/lib/i686/cmov/libc-2.7.so + obj:/lib/i686/cmov/libc-2.7.so + obj:/lib/i686/cmov/libc-2.7.so + obj:/lib/i686/cmov/libc-2.7.so + fun:iconv_open +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libc-2.7.so + obj:/lib/ld-2.7.so + fun:__libc_dlopen_mode + obj:/lib/i686/cmov/libc-2.7.so + obj:/lib/i686/cmov/libc-2.7.so + obj:/lib/i686/cmov/libc-2.7.so + obj:/lib/i686/cmov/libc-2.7.so + obj:/lib/i686/cmov/libc-2.7.so + fun:iconv_open +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + fun:dlopen +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + fun:dlopen +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + fun:dlopen +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + fun:dlopen +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + fun:dlopen +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + fun:dlopen +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + fun:dlopen +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + fun:dlopen +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + fun:dlopen +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + fun:dlopen +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + fun:dlopen +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + fun:dlopen +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + obj:/lib/ld-2.7.so + obj:/lib/i686/cmov/libdl-2.7.so + fun:dlopen +} + +# suppression for a glibc bug: +# http://valgrind.org/docs/manual/faq.html#faq.exit_errors> +{ + + Memcheck:Free + fun:free + obj:*libc-*.so + fun:__libc_freeres + fun:* + fun:_Exit +} + +# valgrind doesn't allow me to specify a suppression for Addr1, Addr2, Addr4 +# as Addr*, so 3 copies for that; and then 2 of each for that pesky memcpy +{ + + Memcheck:Addr1 + fun:_dl_signal_error + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open +} + +{ + + Memcheck:Addr2 + fun:_dl_signal_error + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open +} +{ + + Memcheck:Addr4 + fun:_dl_signal_error + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open +} + +{ + + Memcheck:Addr1 + fun:memcpy + fun:_dl_signal_error + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open +} + +{ + + Memcheck:Addr2 + fun:memcpy + fun:_dl_signal_error + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open +} +{ + + Memcheck:Addr4 + fun:memcpy + fun:_dl_signal_error + fun:_dl_map_object_deps + fun:dl_open_worker + fun:_dl_catch_error + fun:_dl_open + fun:dlopen_doit + fun:_dl_catch_error + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 + fun:g_module_open +} + +{ + + Memcheck:Addr8 + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/libc-2.3.*.so + obj:/lib/ld-2.3.*.so + fun:_dl_open + obj:/lib/libdl-2.3.*.so + obj:/lib/ld-2.3.*.so +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.3.*.so + obj:/lib/libc-2.3.*.so + obj:/lib/ld-2.3.*.so + fun:_dl_open + obj:/lib/libdl-2.3.*.so + obj:/lib/ld-2.3.*.so + obj:/lib/libdl-2.3.*.so + fun:dlopen + fun:g_module_open + fun:gst_plugin_load_file + fun:gst_plugin_load_by_name + fun:gst_plugin_feature_load +} + +{ + + Memcheck:Addr4 + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/tls/i686/cmov/libc-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:_dl_open + obj:/lib/tls/i686/cmov/libdl-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/tls/i686/cmov/libdl-2.3.6.so + fun:dlopen +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.3.6.so + obj:/lib/tls/i686/cmov/libc-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:_dl_open + obj:/lib/tls/i686/cmov/libdl-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/tls/i686/cmov/libdl-2.3.6.so + fun:dlopen +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/tls/i686/cmov/libc-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:_dl_open + obj:/lib/tls/i686/cmov/libdl-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/tls/i686/cmov/libdl-2.3.6.so + fun:dlopen +} + +### glib suppressions +{ + + Memcheck:Cond + fun:g_parse_debug_string + obj:/usr/lib*/libglib-2.0.so.* + fun:g_slice_alloc + fun:g_slice_alloc0 +} + +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:g_strdup + fun:g_quark_from_string + obj:* + obj:* + fun:g_type_register_fundamental + obj:* + fun:g_type_init_with_debug_flags + fun:g_type_init + fun:init_pre +} + +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + obj:* + obj:* + fun:g_type_register_fundamental +} + +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + obj:* + obj:* + fun:g_type_init_with_debug_flags +} + +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:g_slice_alloc + obj:* + obj:* + fun:g_type_init_with_debug_flags +} + +#pthread memleaks + +{ + Thread creation leak + Memcheck:Leak + fun:calloc + fun:allocate_dtv + fun:_dl_allocate* + fun:_dl_allocate* + fun:__pthread_initialize_minimal +} + +{ + Thread management leak + Memcheck:Leak + fun:calloc + fun:allocate_dtv + fun:_dl_allocate* + fun:_dl_allocate* + fun:__pthread_* +} + +{ + Thread management leak 2 + Memcheck:Leak + fun:memalign + fun:_dl_allocate* + fun:_dl_allocate* + fun:__pthread_* +} + +{ + pthread_create Syscall param write(buf) points to uninitialised byte(s) + Memcheck:Param + write(buf) + fun:pthread_create@@GLIBC_2.2.5 + fun:g_thread_create* + +} + +# nss_parse_* memleak (used by g_option_context_parse) +{ + nss_parse_* memleak + Memcheck:Leak + fun:malloc + fun:nss_parse_service_list + fun:__nss_database_lookup +} + +# liboil suppressions +{ + + Memcheck:Value8 + obj:/usr/lib/liboil-0.3.so.0.1.0 + obj:/usr/lib/liboil-0.3.so.0.1.0 + obj:/usr/lib/liboil-0.3.so.0.1.0 + fun:oil_cpu_fault_check_try + fun:oil_test_check_impl + fun:oil_class_optimize + fun:oil_optimize_all + fun:oil_init +} + +{ + + Memcheck:Addr8 + obj:/lib/ld-2.3.6.so +} + +{ + + Memcheck:Param + futex(uaddr2) + fun:pthread_once + obj:/lib/libc-2.3.6.so + obj:/lib/libc-2.3.6.so + fun:setlocale + fun:init_pre + fun:g_option_context_parse + fun:gst_init_check + fun:gst_init + fun:gst_check_init + fun:main +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:_dl_open + obj:/lib/libdl-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/libdl-2.3.6.so + fun:dlopen + fun:g_module_open + fun:gst_plugin_load_file +} +# this exists in a bunch of different variations, hence the short tail/trace +{ + + Memcheck:Addr4 + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so +} +{ + + Memcheck:Addr8 + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so +} + +# More edgy suppressions (Mike) +{ + + Memcheck:Cond + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + fun:dlopen_doit + obj:/lib/ld-2.4.so + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + fun:dlopen_doit + obj:/lib/ld-2.4.so + fun:_dlerror_run + fun:dlopen@@GLIBC_2.1 +} + +{ + + Memcheck:Cond + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + fun:do_sym + fun:_dl_sym +} + +# This one's overly general, but there's zero other information in the stack +# trace - just these five lines! +{ + + Memcheck:Cond + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so + obj:/lib/ld-2.4.so +} + +{ + + Memcheck:Leak + fun:calloc + obj:/lib/ld-2.4.so + fun:_dl_allocate_tls + fun:pthread_create@@GLIBC_2.1 +} + +# TLS leaks for feisty/x86 +{ + + Memcheck:Leak + fun:calloc + fun:allocate_dtv + fun:_dl_allocate_tls + fun:pthread_create@@GLIBC_2.1 +} + +{ + + Memcheck:Leak + fun:calloc + obj:/usr/lib/libcdio.so.6.0.1 + fun:cdio_open_am_linux + obj:/usr/lib/libcdio.so.6.0.1 + fun:cdio_open_am +} + +{ + + Memcheck:Addr8 + obj:/lib/ld-2.5.so +} + +{ + + Memcheck:Cond + fun:snd_pcm_direct_shm_create_or_connect + fun:snd_pcm_dsnoop_open + fun:_snd_pcm_dsnoop_open + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_pcm_open_slave + fun:_snd_pcm_plug_open + obj:/*lib/libasound.so.2.0.0 + fun:snd_pcm_open_slave + fun:_snd_pcm_asym_open + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 +} + +{ + + Memcheck:Cond + fun:snd_pcm_hw_param_set_near + fun:set_hwparams +} + +{ + + Memcheck:Cond + fun:_snd_pcm_hw_param_set_min + fun:snd_pcm_hw_param_set_min + fun:snd_pcm_hw_param_set_near + fun:set_hwparams +} + +{ + + Memcheck:Cond + fun:_snd_pcm_hw_param_set_min + fun:snd_pcm_hw_param_set_min + fun:snd_pcm_hw_param_set_near + fun:set_hwparams +} + +{ + + Memcheck:Cond + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_pcm_hw_param_set_near + fun:set_hwparams +} +{ + + Memcheck:Cond + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_pcm_close + obj:/*lib/libasound.so.2.0.0 +} +{ + + Memcheck:Cond + fun:snd_pcm_direct_shm_create_or_connect + fun:snd_pcm_dmix_open + fun:_snd_pcm_dmix_open + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_pcm_open_slave + fun:_snd_pcm_softvol_open + obj:/*lib/libasound.so.2.0.0 + fun:snd_pcm_open_slave + fun:_snd_pcm_plug_open + obj:/*lib/libasound.so.2.0.0 + fun:snd_pcm_open_slave + fun:_snd_pcm_asym_open + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 +} +{ + + Memcheck:Leak + fun:malloc + fun:strdup + fun:snd_dlobj_cache_add + obj:/*lib/libasound.so.2.0.0 + fun:snd_pcm_open_slave + fun:snd_pcm_dsnoop_open + fun:_snd_pcm_dsnoop_open + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_pcm_open_slave + fun:_snd_pcm_plug_open + obj:/*lib/libasound.so.2.0.0 + fun:snd_pcm_open_slave + fun:_snd_pcm_asym_open + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 +} +# Catch about 15 variations on inserting info into an ALSA +# internal cache +{ + + Memcheck:Leak + fun:malloc + fun:snd_dlobj_cache_add + obj:/*lib/libasound.so.2.0.0 +} +{ + + Memcheck:Leak + fun:malloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks +} +{ + + Memcheck:Leak + fun:malloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + fun:snd_config_hook_load_for_all_cards + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks + fun:snd_config_search_alias_hooks + fun:snd_config_search_definition +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + fun:snd_config_hook_load_for_all_cards + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks + fun:snd_config_search_alias_hooks + fun:snd_config_search_definition +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks + fun:snd_config_search_alias_hooks + fun:snd_config_search_definition +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_update_r + fun:snd_config_update +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_update_r + fun:snd_config_update +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_update_r + fun:snd_config_update +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_update_r + fun:snd_config_update +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_update_r + fun:snd_config_update +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_update_r + fun:snd_config_update +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_update_r + fun:snd_config_update +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_update_r + fun:snd_config_update +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_update_r + fun:snd_config_update +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_update_r + fun:snd_config_update +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks + fun:snd_config_search_alias_hooks + fun:snd_config_search_definition + obj:/*lib/libasound.so.2.0.0 +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks + fun:snd_config_search_alias_hooks + fun:snd_config_search_definition + obj:/*lib/libasound.so.2.0.0 +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + fun:snd_config_hook_load_for_all_cards + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks + fun:snd_config_search_alias_hooks + fun:snd_config_search_definition + obj:/*lib/libasound.so.2.0.0 +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + fun:snd_config_hook_load_for_all_cards + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks + fun:snd_config_search_alias_hooks + fun:snd_config_search_definition + obj:/*lib/libasound.so.2.0.0 +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + fun:snd_config_hook_load_for_all_cards + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks + fun:snd_config_search_alias_hooks + fun:snd_config_search_definition + obj:/*lib/libasound.so.2.0.0 +} +{ + + Memcheck:Leak + fun:calloc + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_hook_load + fun:snd_config_hook_load_for_all_cards + obj:/*lib/libasound.so.2.0.0 + fun:snd_config_searcha_hooks + fun:snd_config_search_alias_hooks + fun:snd_config_search_definition + obj:/*lib/libasound.so.2.0.0 +} +{ + + Memcheck:Leak + fun:malloc + obj:/lib/libc*.so + fun:__nss_database_lookup + obj:* + obj:* + fun:getgrnam_r + fun:getgrnam + fun:snd_pcm_direct_parse_open_conf +} + +{ + + Memcheck:Leak + fun:calloc + fun:_XCBInitDisplayLock + fun:XOpenDisplay +} + +# GConf internal initialisations related to getting the default client. +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc_tcval + obj:/usr/lib/libORBit-2.so.* + fun:ORBit_demarshal_IOR + fun:ORBit_demarshal_object + fun:CORBA_ORB_string_to_object + obj:/usr/lib/libgconf-2.so.* + fun:gconf_get_current_lock_holder + fun:gconf_activate_server + obj:/usr/lib/libgconf-2.so.* + obj:/usr/lib/libgconf-2.so.* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc_tcval + obj:/usr/lib/libORBit-2.so.* + fun:PortableServer_POA_servant_to_reference + obj:/usr/lib/libgconf-2.so.* + obj:/usr/lib/libgconf-2.so.* + obj:/usr/lib/libgconf-2.so.* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc_tcval + obj:/usr/lib/libORBit-2.so.* + fun:ORBit_demarshal_IOR + fun:ORBit_demarshal_object + fun:CORBA_ORB_string_to_object + obj:/usr/lib/libgconf-2.so.* + fun:gconf_get_current_lock_holder + fun:gconf_activate_server + obj:/usr/lib/libgconf-2.so.* + obj:/usr/lib/libgconf-2.so.* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc* + obj:/usr/lib/libORBit-2.so.* + fun:ORBit_demarshal_IOR + fun:ORBit_demarshal_object + fun:ORBit_demarshal_value + obj:/usr/lib/libORBit-2.so.* + fun:ORBit_small_invoke_stub + fun:ConfigServer_get_default_database + obj:/usr/lib/libgconf-2.so.* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc* + obj:/usr/lib/libORBit-2.so.* + fun:IOP_generate_profiles + fun:ORBit_marshal_object + fun:ORBit_marshal_value + obj:/usr/lib/libORBit-2.so.* + fun:ORBit_small_invoke_stub + fun:ConfigServer_add_client + obj:/usr/lib/libgconf-2.so.* + obj:/usr/lib/libgconf-2.so.* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc_by_tc + obj:/usr/lib/libORBit-2.so.* + fun:PortableServer_POA_servant_to_reference + obj:/usr/lib/libgconf-2.so.* + obj:/usr/lib/libgconf-2.so.* + obj:/usr/lib/libgconf-2.so.* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc_by_tc + obj:/usr/lib/libORBit-2.so.* + fun:ORBit_demarshal_IOR + fun:ORBit_demarshal_object + fun:CORBA_ORB_string_to_object + obj:/usr/lib/libgconf-2.so.* + fun:gconf_get_current_lock_holder + fun:gconf_activate_server + obj:/usr/lib/libgconf-2.so.* + obj:/usr/lib/libgconf-2.so.* + fun:gconf_engine_get_default +} + +# Some libORBit/bonobo initialisation stuff +{ + + Memcheck:Leak + fun:malloc + fun:g_malloc + fun:ORBit_alloc_string + fun:CORBA_string_dup + fun:Bonobo_ActivationEnvValue_set + fun:bonobo_activation_init_activation_env + fun:bonobo_activation_orb_init + fun:bonobo_activation_init +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc* + fun:ORBit_small_alloc* + obj:/usr/lib/libORBit-2.so* + fun:PortableServer_POA_servant_to_reference + obj:/usr/lib/libbonobo-2.so* +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc_tcval + fun:ORBit_small_allocbuf + fun:ORBit_adaptor_setup + obj:/usr/lib/libORBit-2.so* + fun:ORBit_POA_setup_root + fun:ORBit_init_internals + fun:CORBA_ORB_init +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc_tcval + fun:ORBit_adaptor_setup + obj:/usr/lib/libORBit-2.so* + fun:ORBit_POA_setup_root + fun:ORBit_init_internals + fun:CORBA_ORB_init +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc* + fun:ORBit_small_allocbuf + fun:bonobo_activation_init_activation_env + fun:bonobo_activation_orb_init + fun:bonobo_activation_init +} + +# More GConf stuff from the FC5 buildbot, mostly variations on the +# above stack traces +{ + + Memcheck:Param + writev(vector[...]) + fun:writev + obj:/usr/lib/libORBit-2.so* + fun:link_connection_writev + fun:giop_send_buffer_write + obj:/usr/lib/libORBit-2.so* + fun:ORBit_small_invoke_stub + fun:ORBit_small_invoke_stub_n + fun:ORBit_c_stub_invoke + fun:ConfigServer_ping + fun:gconf_activate_server + obj:/usr/lib/libgconf-2.so* + obj:/usr/lib/libgconf-2.so* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc* + fun:ORBit_small_alloc* + obj:/usr/lib/libORBit-2.so* + fun:PortableServer_POA_servant_to_reference + obj:/usr/lib/libgconf-2.so* + obj:/usr/lib/libgconf-2.so* + obj:/usr/lib/libgconf-2.so* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc* + fun:ORBit_small_alloc + obj:/usr/lib/libORBit-2.so* + fun:ORBit_demarshal_IOR + fun:ORBit_demarshal_object + fun:CORBA_ORB_string_to_object + obj:/usr/lib/libgconf-2.so* + fun:gconf_get_current_lock_holder + fun:gconf_activate_server + obj:/usr/lib/libgconf-2.so* + obj:/usr/lib/libgconf-2.so* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc* + fun:ORBit_small_alloc* + obj:/usr/lib/libORBit-2.so* + fun:ORBit_demarshal_IOR + fun:ORBit_demarshal_object + fun:CORBA_ORB_string_to_object + obj:/usr/lib/libgconf-2.so* + fun:gconf_get_current_lock_holder + fun:gconf_activate_server + obj:/usr/lib/libgconf-2.so* + obj:/usr/lib/libgconf-2.so* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc* + fun:ORBit_small_alloc* + obj:/usr/lib/libORBit-2.so* + fun:ORBit_demarshal_IOR + fun:ORBit_demarshal_object + fun:ORBit_demarshal_value + obj:/usr/lib/libORBit-2.so* + fun:ORBit_small_invoke_stub + fun:ORBit_small_invoke_stub_n + fun:ORBit_c_stub_invoke + fun:ConfigServer_get_default_database + obj:/usr/lib/libgconf-2.so* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:ORBit_alloc* + fun:ORBit_small_alloc* + obj:/usr/lib/libORBit-2.so* + fun:ORBit_OAObject_object_to_objkey + fun:IOP_generate_profiles + fun:ORBit_marshal_object + fun:ORBit_marshal_value + obj:/usr/lib/libORBit-2.so* + fun:ORBit_small_invoke_stub + fun:ORBit_small_invoke_stub_n + fun:ORBit_c_stub_invoke + fun:ConfigServer_add_client + obj:/usr/lib/libgconf-2.so* + obj:/usr/lib/libgconf-2.so* + fun:gconf_engine_get_default +} +{ + + Memcheck:Leak + fun:malloc + obj:*libc-*.so + fun:__nss_database_lookup + obj:* + obj:* + fun:getpwnam_r + obj:/usr/lib*/libglib-2.0.so.* + fun:g_get_home_dir +} +{ + + Memcheck:Leak + fun:malloc + obj:*libc-*.so + fun:__nss_database_lookup + obj:* + obj:* + fun:getpwnam_r + obj:/usr/lib*/libglib-2.0.so.* + fun:g_get_user_name +} +{ + + Memcheck:Leak + fun:malloc + obj:*libc-*.so + fun:__nss_database_lookup + obj:* + obj:* + fun:getpwnam_r + obj:/usr/lib*/libglib-2.0.so.* + fun:g_get_tmp_dir +} + +{ + + Memcheck:Leak + fun:malloc + obj:*libc-*.so + fun:__nss_database_lookup + obj:* + obj:* + fun:getpwnam_r + obj:/usr/lib*/libglib-2.0.so.0.* + fun:g_get_host_name +} + + +## Some Fontconfig errors. +{ + + Memcheck:Leak + fun:malloc + fun:FcPatternObjectInsertElt + fun:FcPatternObjectAddWithBinding + fun:FcPatternAppend + fun:FcEndElement + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + fun:XML_ParseBuffer + fun:FcConfigParseAndLoad + fun:FcConfigParseAndLoad + fun:FcParseInclude + fun:FcEndElement + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + fun:XML_ParseBuffer + fun:FcConfigParseAndLoad +} +{ + + Memcheck:Leak + fun:malloc + fun:FcStrCopy + fun:FcEndElement + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + fun:XML_ParseBuffer + fun:FcConfigParseAndLoad + fun:FcConfigParseAndLoad + fun:FcParseInclude + fun:FcEndElement + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + obj:/usr/lib/libexpat.so.1.0.0 + fun:XML_ParseBuffer + fun:FcConfigParseAndLoad + fun:FcInitLoadConfig + fun:FcInitLoadConfigAndFonts +} + diff --git a/common/gstdoc-scangobj b/common/gstdoc-scangobj new file mode 100755 index 0000000..90ba889 --- /dev/null +++ b/common/gstdoc-scangobj @@ -0,0 +1,1607 @@ +#!/usr/bin/perl -w +# -*- cperl -*- +# +# gtk-doc - GTK DocBook documentation generator. +# Copyright (C) 1998 Damon Chaplin +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +# +# This gets information about object heirarchies and signals +# by compiling a small C program. CFLAGS and LDFLAGS must be +# set appropriately before running this script. +# +# NOTE: the lookup_signal_arg_names() function contains the argument names of +# standard GTK signal handlers. This may need to be updated for new +# GTK signals or Gnome widget signals. + +use Getopt::Long; + +unshift @INC, '/usr/share/gtk-doc/data'; +require "gtkdoc-common.pl"; + +# Options + +# name of documentation module +my $MODULE; +my $OUTPUT_DIR; +my $PRINT_VERSION; +my $PRINT_HELP; +my $TYPE_INIT_FUNC="g_type_init ()"; + +# --nogtkinit is deprecated, as it is the default now anyway. +%optctl = (module => \$MODULE, + source => \$SOURCE, + types => \$TYPES_FILE, + nogtkinit => \$NO_GTK_INIT, + 'type-init-func' => \$TYPE_INIT_FUNC, + 'output-dir' => \$OUTPUT_DIR, + 'version' => \$PRINT_VERSION, + 'help' => \$PRINT_HELP); + +GetOptions(\%optctl, "module=s", "source=s", "types:s", "output-dir:s", "nogtkinit", "type-init-func:s", "version", "help"); + +if ($NO_GTK_INIT) { + # Do nothing. This just avoids a warning. +} + +if ($PRINT_VERSION) { + print "1.5\n"; + exit 0; +} + +if (!$MODULE) { + $PRINT_HELP = 1; +} + +if ($PRINT_HELP) { + print "gstdoc-scangobj version 1.5\n"; + print "\n--module=MODULE_NAME Name of the doc module being parsed"; + print "\n--source=SOURCE_NAME Name of the source module for plugins"; + print "\n--types=FILE The name of the file to store the types in"; + print "\n--type-init-func=FUNC The init function to call instead of g_type_init ()"; + print "\n--output-dir=DIRNAME The directory where the results are stored"; + print "\n--version Print the version of this program"; + print "\n--help Print this help\n"; + exit 0; +} + +$OUTPUT_DIR = $OUTPUT_DIR ? $OUTPUT_DIR : "."; + +# THOMAS: dynamic types; only use types file for headers + $TYPES_FILE = $TYPES_FILE ? $TYPES_FILE : "$OUTPUT_DIR/$MODULE.types"; + +open (TYPES, $TYPES_FILE) || die "Cannot open $TYPES_FILE: $!\n"; +open (OUTPUT, ">$MODULE-scan.c") || die "Cannot open $MODULE-scan.c: $!\n"; + +my $old_signals_filename = "$OUTPUT_DIR/$MODULE.signals"; +my $new_signals_filename = "$OUTPUT_DIR/$MODULE.signals.new"; +my $old_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy"; +my $new_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy.new"; +my $old_interfaces_filename = "$OUTPUT_DIR/$MODULE.interfaces"; +my $new_interfaces_filename = "$OUTPUT_DIR/$MODULE.interfaces.new"; +my $old_prerequisites_filename = "$OUTPUT_DIR/$MODULE.prerequisites"; +my $new_prerequisites_filename = "$OUTPUT_DIR/$MODULE.prerequisites.new"; +my $old_args_filename = "$OUTPUT_DIR/$MODULE.args"; +my $new_args_filename = "$OUTPUT_DIR/$MODULE.args.new"; + +# write a C program to scan the types + +$includes = ""; +#@types = (); + +for () { + if (/^#include/) { + $includes .= $_; +# } elsif (/^%/) { +# next; +# } elsif (/^\s*$/) { +# next; +# } else { +# chomp; +# push @types, $_; + } +} + +#$ntypes = @types + 1; + +print OUTPUT < +#include +#include +#include + +$includes +#ifdef GTK_IS_WIDGET_CLASS +#include +#endif +GType *object_types = NULL; + +static GType * +get_object_types (void) +{ + GList *plugins = NULL; + GList *factories = NULL; + GList *l; + GstElementFactory *factory = NULL; + + gint i = 0; + + /* get a list of features from plugins in our source module */ + plugins = gst_registry_get_plugin_list (gst_registry_get_default()); + + while (plugins) { + GList *features; + GstPlugin *plugin; + const gchar *source; + + plugin = (GstPlugin *) (plugins->data); + plugins = g_list_next (plugins); + source = gst_plugin_get_source (plugin); + /*g_print ("plugin: %s source: %s\\n", plugin->desc.name, source);*/ + if (!source || strcmp (source, "$SOURCE") != 0) { + continue; + } + g_print ("plugin: %s source: %s\\n", plugin->desc.name, source); + + features = + gst_registry_get_feature_list_by_plugin (gst_registry_get_default (), + plugin->desc.name); + while (features) { + GstPluginFeature *feature; + feature = GST_PLUGIN_FEATURE (features->data); + feature = gst_plugin_feature_load (feature); + if (!feature) { + g_warning ("Could not load plugin feature %s", + gst_plugin_feature_get_name (feature)); + } + + if (GST_IS_ELEMENT_FACTORY (feature)) { + factory = GST_ELEMENT_FACTORY (feature); + factories = g_list_prepend (factories, factory); + } + features = g_list_next (features); + } + } + + g_message ("number of element factories: %d", g_list_length (factories)); + + /* allocate the object_types array to hold them */ + object_types = g_new0 (GType, g_list_length (factories)+1); + + l = factories; + i = 0; + + /* fill it */ + while (l) { + GType type; + factory = GST_ELEMENT_FACTORY (l->data); + type = gst_element_factory_get_element_type (factory); + g_message ("adding type %p for factory %s", (void *) type, gst_element_factory_get_longname (factory)); + object_types[i] = type; + i++; + l = g_list_next (l); + } + object_types[i] = 0; +EOT + +print OUTPUT <\\n%s::%s\\n%s\\n%s\\n%s\\n\\n", + object_name, query_info.signal_name, ret_type_buffer, flags, buffer); +} + + +/* Returns the type name to use for a signal argument or return value, given + the GtkType from the signal info. It also sets is_pointer to TRUE if the + argument needs a '*' since it is a pointer. */ +static const gchar * +get_type_name (GType type, gboolean * is_pointer) +{ + const gchar *type_name; + + *is_pointer = FALSE; + type_name = g_type_name (type); + + switch (type) { + case G_TYPE_NONE: + case G_TYPE_CHAR: + case G_TYPE_UCHAR: + case G_TYPE_BOOLEAN: + case G_TYPE_INT: + case G_TYPE_UINT: + case G_TYPE_LONG: + case G_TYPE_ULONG: + case G_TYPE_FLOAT: + case G_TYPE_DOUBLE: + case G_TYPE_POINTER: + /* These all have normal C type names so they are OK. */ + return type_name; + + case G_TYPE_STRING: + /* A GtkString is really a gchar*. */ + *is_pointer = TRUE; + return "gchar"; + + case G_TYPE_ENUM: + case G_TYPE_FLAGS: + /* We use a gint for both of these. Hopefully a subtype with a decent + name will be registered and used instead, as GTK+ does itself. */ + return "gint"; + + case G_TYPE_BOXED: + /* The boxed type shouldn't be used itself, only subtypes. Though we + return 'gpointer' just in case. */ + return "gpointer"; + + case G_TYPE_PARAM: + /* A GParam is really a GParamSpec*. */ + *is_pointer = TRUE; + return "GParamSpec"; + + default: + break; + } + + /* For all GObject subclasses we can use the class name with a "*", + e.g. 'GtkWidget *'. */ + if (g_type_is_a (type, G_TYPE_OBJECT)) + *is_pointer = TRUE; + + if (G_TYPE_IS_CLASSED (type)) + *is_pointer = TRUE; + + /* All boxed subtypes will be pointers as well. */ + if (g_type_is_a (type, G_TYPE_BOXED)) + *is_pointer = TRUE; + + /* All pointer subtypes will be pointers as well. */ + if (g_type_is_a (type, G_TYPE_POINTER)) + *is_pointer = TRUE; + + /* But enums are not */ + if (g_type_is_a (type, G_TYPE_ENUM) || + g_type_is_a (type, G_TYPE_FLAGS)) + *is_pointer = FALSE; + + return type_name; +} + + +static const gchar * +get_gdk_event (const gchar * signal_name) +{ + static const gchar *GbGDKEvents[] = + { + "button_press_event", "GdkEventButton", + "button_release_event", "GdkEventButton", + "motion_notify_event", "GdkEventMotion", + "delete_event", "GdkEvent", + "destroy_event", "GdkEvent", + "expose_event", "GdkEventExpose", + "key_press_event", "GdkEventKey", + "key_release_event", "GdkEventKey", + "enter_notify_event", "GdkEventCrossing", + "leave_notify_event", "GdkEventCrossing", + "configure_event", "GdkEventConfigure", + "focus_in_event", "GdkEventFocus", + "focus_out_event", "GdkEventFocus", + "map_event", "GdkEvent", + "unmap_event", "GdkEvent", + "property_notify_event", "GdkEventProperty", + "selection_clear_event", "GdkEventSelection", + "selection_request_event", "GdkEventSelection", + "selection_notify_event", "GdkEventSelection", + "proximity_in_event", "GdkEventProximity", + "proximity_out_event", "GdkEventProximity", + "drag_begin_event", "GdkEventDragBegin", + "drag_request_event", "GdkEventDragRequest", + "drag_end_event", "GdkEventDragRequest", + "drop_enter_event", "GdkEventDropEnter", + "drop_leave_event", "GdkEventDropLeave", + "drop_data_available_event", "GdkEventDropDataAvailable", + "other_event", "GdkEventOther", + "client_event", "GdkEventClient", + "no_expose_event", "GdkEventNoExpose", + "visibility_notify_event", "GdkEventVisibility", + "window_state_event", "GdkEventWindowState", + "scroll_event", "GdkEventScroll", + NULL + }; + + gint i; + + for (i = 0; GbGDKEvents[i]; i += 2) + { + if (!strcmp (signal_name, GbGDKEvents[i])) + return GbGDKEvents[i + 1]; + } + return "GdkEvent"; +} + + +/* This returns argument names to use for some known GTK signals. + It is passed a widget name, e.g. 'GtkCList' and a signal name, e.g. + 'select_row' and it returns a pointer to an array of argument types and + names. */ +static const gchar ** +lookup_signal_arg_names (const gchar * type, const gchar * signal_name) +{ + /* Each arg array starts with the object type name and the signal name, + and then signal arguments follow. */ + static const gchar *GbArgTable[][16] = + { + {"GtkCList", "select_row", + "gint row", + "gint column", + "GdkEventButton *event"}, + {"GtkCList", "unselect_row", + "gint row", + "gint column", + "GdkEventButton *event"}, + {"GtkCList", "click_column", + "gint column"}, + + {"GtkCList", "resize_column", + "gint column", + "gint width"}, + + {"GtkCList", "extend_selection", + "GtkScrollType scroll_type", + "gfloat position", + "gboolean auto_start_selection"}, + {"GtkCList", "scroll_vertical", + "GtkScrollType scroll_type", + "gfloat position"}, + {"GtkCList", "scroll_horizontal", + "GtkScrollType scroll_type", + "gfloat position"}, + + {"GtkCTree", "tree_select_row", + "GtkCTreeNode *node", + "gint column"}, + {"GtkCTree", "tree_unselect_row", + "GtkCTreeNode *node", + "gint column"}, + {"GtkCTree", "tree_expand", + "GtkCTreeNode *node"}, + {"GtkCTree", "tree_collapse", + "GtkCTreeNode *node"}, + {"GtkCTree", "tree_move", + "GtkCTreeNode *node", + "GtkCTreeNode *new_parent", + "GtkCTreeNode *new_sibling"}, + {"GtkCTree", "change_focus_row_expansion", + "GtkCTreeExpansionType expansion"}, + + {"GtkEditable", "insert_text", + "gchar *new_text", + "gint new_text_length", + "gint *position"}, + {"GtkEditable", "delete_text", + "gint start_pos", + "gint end_pos"}, + {"GtkEditable", "set_editable", + "gboolean is_editable"}, + {"GtkEditable", "move_cursor", + "gint x", + "gint y"}, + {"GtkEditable", "move_word", + "gint num_words"}, + {"GtkEditable", "move_page", + "gint x", + "gint y"}, + {"GtkEditable", "move_to_row", + "gint row"}, + {"GtkEditable", "move_to_column", + "gint column"}, + + {"GtkEditable", "kill_char", + "gint direction"}, + {"GtkEditable", "kill_word", + "gint direction"}, + {"GtkEditable", "kill_line", + "gint direction"}, + + + {"GtkInputDialog", "enable_device", + "GdkDevice *deviceid"}, + {"GtkInputDialog", "disable_device", + "GdkDevice *deviceid"}, + + {"GtkListItem", "extend_selection", + "GtkScrollType scroll_type", + "gfloat position", + "gboolean auto_start_selection"}, + {"GtkListItem", "scroll_vertical", + "GtkScrollType scroll_type", + "gfloat position"}, + {"GtkListItem", "scroll_horizontal", + "GtkScrollType scroll_type", + "gfloat position"}, + + {"GtkMenuShell", "move_current", + "GtkMenuDirectionType direction"}, + {"GtkMenuShell", "activate_current", + "gboolean force_hide"}, + + + {"GtkNotebook", "switch_page", + "GtkNotebookPage *page", + "guint page_num"}, + {"GtkStatusbar", "text_pushed", + "guint context_id", + "gchar *text"}, + {"GtkStatusbar", "text_popped", + "guint context_id", + "gchar *text"}, + {"GtkTipsQuery", "widget_entered", + "GtkWidget *widget", + "gchar *tip_text", + "gchar *tip_private"}, + {"GtkTipsQuery", "widget_selected", + "GtkWidget *widget", + "gchar *tip_text", + "gchar *tip_private", + "GdkEventButton *event"}, + {"GtkToolbar", "orientation_changed", + "GtkOrientation orientation"}, + {"GtkToolbar", "style_changed", + "GtkToolbarStyle style"}, + {"GtkWidget", "draw", + "GdkRectangle *area"}, + {"GtkWidget", "size_request", + "GtkRequisition *requisition"}, + {"GtkWidget", "size_allocate", + "GtkAllocation *allocation"}, + {"GtkWidget", "state_changed", + "GtkStateType state"}, + {"GtkWidget", "style_set", + "GtkStyle *previous_style"}, + + {"GtkWidget", "install_accelerator", + "gchar *signal_name", + "gchar key", + "gint modifiers"}, + + {"GtkWidget", "add_accelerator", + "guint accel_signal_id", + "GtkAccelGroup *accel_group", + "guint accel_key", + "GdkModifierType accel_mods", + "GtkAccelFlags accel_flags"}, + + {"GtkWidget", "parent_set", + "GtkObject *old_parent"}, + + {"GtkWidget", "remove_accelerator", + "GtkAccelGroup *accel_group", + "guint accel_key", + "GdkModifierType accel_mods"}, + {"GtkWidget", "debug_msg", + "gchar *message"}, + {"GtkWindow", "move_resize", + "gint *x", + "gint *y", + "gint width", + "gint height"}, + {"GtkWindow", "set_focus", + "GtkWidget *widget"}, + + {"GtkWidget", "selection_get", + "GtkSelectionData *data", + "guint info", + "guint time"}, + {"GtkWidget", "selection_received", + "GtkSelectionData *data", + "guint time"}, + + {"GtkWidget", "drag_begin", + "GdkDragContext *drag_context"}, + {"GtkWidget", "drag_end", + "GdkDragContext *drag_context"}, + {"GtkWidget", "drag_data_delete", + "GdkDragContext *drag_context"}, + {"GtkWidget", "drag_leave", + "GdkDragContext *drag_context", + "guint time"}, + {"GtkWidget", "drag_motion", + "GdkDragContext *drag_context", + "gint x", + "gint y", + "guint time"}, + {"GtkWidget", "drag_drop", + "GdkDragContext *drag_context", + "gint x", + "gint y", + "guint time"}, + {"GtkWidget", "drag_data_get", + "GdkDragContext *drag_context", + "GtkSelectionData *data", + "guint info", + "guint time"}, + {"GtkWidget", "drag_data_received", + "GdkDragContext *drag_context", + "gint x", + "gint y", + "GtkSelectionData *data", + "guint info", + "guint time"}, + + {NULL} + }; + + gint i; + + for (i = 0; GbArgTable[i][0]; i++) + { +#if 1 + if (!strcmp (type, GbArgTable[i][0]) + && !strcmp (signal_name, GbArgTable[i][1])) + return &GbArgTable[i][2]; +#endif + } + return NULL; +} + +/* This outputs the hierarchy of all objects which have been initialized, + i.e. by calling their XXX_get_type() initialization function. */ +static void +output_object_hierarchy (void) +{ + FILE *fp; + gint i; + + fp = fopen (hierarchy_filename, "w"); + if (fp == NULL) + { + g_warning ("Couldn't open output file: %s : %s", hierarchy_filename, strerror(errno)); + return; + } + output_hierarchy (fp, G_TYPE_OBJECT, 0); + output_hierarchy (fp, G_TYPE_INTERFACE, 0); + + for (i=0; object_types[i]; i++) { + if (!g_type_parent (object_types[i]) && + (object_types[i] != G_TYPE_NONE) && + (object_types[i] != G_TYPE_OBJECT) && + (object_types[i] != G_TYPE_INTERFACE) + ) { + g_warning ("printing hierarchy for root type: %s", + g_type_name (object_types[i])); + output_hierarchy (fp, object_types[i], 0); + } + } + /* for debugging + for (i=0; object_types[i]; i++) { + if(object_types[i] != G_TYPE_NONE) { + g_print ("type has not been added to hierarchy: %s\\n", + g_type_name (object_types[i])); + } + } + for debugging */ + + fclose (fp); +} + +/* This is called recursively to output the hierarchy of a widget. */ +static void +output_hierarchy (FILE *fp, + GType type, + guint level) +{ + guint i; + GType *children; + guint n_children; + + if (!type) + return; + + /* for debugging + for (i=0; object_types[i]; i++) { + if(object_types[i] == type) { + g_print ("added type to hierarchy (level %d): %s\\n", + level, g_type_name (type)); + object_types[i] = G_TYPE_NONE; + break; + } + } + for debugging */ + + for (i = 0; i < level; i++) + fprintf (fp, " "); + fprintf (fp, g_type_name (type)); + fprintf (fp, "\\n"); + + children = g_type_children (type, &n_children); + + for (i=0; i < n_children; i++) { + output_hierarchy (fp, children[i], level + 1); + } + + g_free (children); +} + +static void output_object_interfaces (void) +{ + guint i; + FILE *fp; + + fp = fopen (interfaces_filename, "w"); + if (fp == NULL) + { + g_warning ("Couldn't open output file: %s : %s", interfaces_filename, strerror(errno)); + return; + } + output_interfaces (fp, G_TYPE_OBJECT); + + for (i = 0; object_types[i]; i++) + { + if (!g_type_parent (object_types[i]) && + (object_types[i] != G_TYPE_OBJECT) && + G_TYPE_IS_INSTANTIATABLE (object_types[i])) + { + output_interfaces (fp, object_types[i]); + } + } + fclose (fp); +} + +static void +output_interfaces (FILE *fp, + GType type) +{ + guint i; + GType *children, *interfaces; + guint n_children, n_interfaces; + + if (!type) + return; + + interfaces = g_type_interfaces (type, &n_interfaces); + + if (n_interfaces > 0) + { + fprintf (fp, g_type_name (type)); + for (i=0; i < n_interfaces; i++) + fprintf (fp, " %s", g_type_name (interfaces[i])); + fprintf (fp, "\\n"); + } + g_free (interfaces); + + children = g_type_children (type, &n_children); + + for (i=0; i < n_children; i++) + output_interfaces (fp, children[i]); + + g_free (children); +} + +static void output_interface_prerequisites (void) +{ + FILE *fp; + + fp = fopen (prerequisites_filename, "w"); + if (fp == NULL) + { + g_warning ("Couldn't open output file: %s : %s", prerequisites_filename, strerror(errno)); + return; + } + output_prerequisites (fp, G_TYPE_INTERFACE); + fclose (fp); +} + +static void +output_prerequisites (FILE *fp, + GType type) +{ +#if GLIB_CHECK_VERSION(2,1,0) + guint i; + GType *children, *prerequisites; + guint n_children, n_prerequisites; + + if (!type) + return; + + prerequisites = g_type_interface_prerequisites (type, &n_prerequisites); + + if (n_prerequisites > 0) + { + fprintf (fp, g_type_name (type)); + for (i=0; i < n_prerequisites; i++) + fprintf (fp, " %s", g_type_name (prerequisites[i])); + fprintf (fp, "\\n"); + } + g_free (prerequisites); + + children = g_type_children (type, &n_children); + + for (i=0; i < n_children; i++) + output_prerequisites (fp, children[i]); + + g_free (children); +#endif +} + +static void +output_args (void) +{ + FILE *fp; + gint i; + + fp = fopen (args_filename, "w"); + if (fp == NULL) + { + g_warning ("Couldn't open output file: %s : %s", args_filename, strerror(errno)); + return; + } + + for (i = 0; object_types[i]; i++) { + output_object_args (fp, object_types[i]); + } + + fclose (fp); +} + +static gint +compare_param_specs (const void *a, const void *b) +{ + GParamSpec *spec_a = *(GParamSpec **)a; + GParamSpec *spec_b = *(GParamSpec **)b; + + return strcmp (g_param_spec_get_name (spec_a), g_param_spec_get_name (spec_b)); +} + +/* Its common to have unsigned properties restricted + * to the signed range. Therefore we make this look + * a bit nicer by spelling out the max constants. + */ + +/* Don't use "==" with floats, it might trigger a gcc warning. */ +#define GTKDOC_COMPARE_FLOAT(x, y) (x <= y && x >= y) + +static gchar* +describe_double_constant (gdouble value) +{ + gchar *desc; + + if (GTKDOC_COMPARE_FLOAT (value, G_MAXDOUBLE)) + desc = g_strdup ("G_MAXDOUBLE"); + else if (GTKDOC_COMPARE_FLOAT (value, G_MINDOUBLE)) + desc = g_strdup ("G_MINDOUBLE"); + else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXDOUBLE)) + desc = g_strdup ("-G_MAXDOUBLE"); + else if (GTKDOC_COMPARE_FLOAT (value, G_MAXFLOAT)) + desc = g_strdup ("G_MAXFLOAT"); + else if (GTKDOC_COMPARE_FLOAT (value, G_MINFLOAT)) + desc = g_strdup ("G_MINFLOAT"); + else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXFLOAT)) + desc = g_strdup ("-G_MAXFLOAT"); + else + desc = g_strdup_printf ("%lg", value); + + return desc; +} + +static gchar* +describe_signed_constant (gint64 value) +{ + gchar *desc; + + if (value == G_MAXINT) + desc = g_strdup ("G_MAXINT"); + else if (value == G_MININT) + desc = g_strdup ("G_MININT"); + else if (value == G_MAXUINT) + desc = g_strdup ("G_MAXUINT"); + else if (value == G_MAXLONG) + desc = g_strdup ("G_MAXLONG"); + else if (value == G_MINLONG) + desc = g_strdup ("G_MINLONG"); + else if (value == G_MAXULONG) + desc = g_strdup ("G_MAXULONG"); + else if (value == G_MAXINT64) + desc = g_strdup ("G_MAXINT64"); + else if (value == G_MININT64) + desc = g_strdup ("G_MININT64"); + else + desc = g_strdup_printf ("%" G_GINT64_FORMAT, value); + + return desc; +} + +static gchar* +describe_unsigned_constant (guint64 value) +{ + gchar *desc; + + if (value == G_MAXINT) + desc = g_strdup ("G_MAXINT"); + else if (value == G_MININT) + desc = g_strdup ("G_MININT"); + else if (value == G_MAXUINT) + desc = g_strdup ("G_MAXUINT"); + else if (value == G_MAXLONG) + desc = g_strdup ("G_MAXLONG"); + else if (value == G_MINLONG) + desc = g_strdup ("G_MINLONG"); + else if (value == G_MAXULONG) + desc = g_strdup ("G_MAXULONG"); + else if (value == G_MAXINT64) + desc = g_strdup ("G_MAXINT64"); + else if (value == G_MININT64) + desc = g_strdup ("G_MININT64"); + else if (value == G_MAXUINT64) + desc = g_strdup ("G_MAXUINT64"); + else + desc = g_strdup_printf ("%" G_GUINT64_FORMAT, value); + + return desc; +} + +static gchar* +describe_type (GParamSpec *spec) +{ + gchar *desc; + gchar *lower; + gchar *upper; + + if (G_IS_PARAM_SPEC_CHAR (spec)) + { + GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec); + + lower = describe_signed_constant (pspec->minimum); + upper = describe_signed_constant (pspec->maximum); + if (pspec->minimum == G_MININT8 && pspec->maximum == G_MAXINT8) + desc = g_strdup (""); + else if (pspec->minimum == G_MININT8) + desc = g_strdup_printf ("<= %s", upper); + else if (pspec->maximum == G_MAXINT8) + desc = g_strdup_printf (">= %s", lower); + else + desc = g_strdup_printf ("[%s,%s]", lower, upper); + g_free (lower); + g_free (upper); + } + else if (G_IS_PARAM_SPEC_UCHAR (spec)) + { + GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec); + + lower = describe_unsigned_constant (pspec->minimum); + upper = describe_unsigned_constant (pspec->maximum); + if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT8) + desc = g_strdup (""); + else if (pspec->minimum == 0) + desc = g_strdup_printf ("<= %s", upper); + else if (pspec->maximum == G_MAXUINT8) + desc = g_strdup_printf (">= %s", lower); + else + desc = g_strdup_printf ("[%s,%s]", lower, upper); + g_free (lower); + g_free (upper); + } + else if (G_IS_PARAM_SPEC_INT (spec)) + { + GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec); + + lower = describe_signed_constant (pspec->minimum); + upper = describe_signed_constant (pspec->maximum); + if (pspec->minimum == G_MININT && pspec->maximum == G_MAXINT) + desc = g_strdup (""); + else if (pspec->minimum == G_MININT) + desc = g_strdup_printf ("<= %s", upper); + else if (pspec->maximum == G_MAXINT) + desc = g_strdup_printf (">= %s", lower); + else + desc = g_strdup_printf ("[%s,%s]", lower, upper); + g_free (lower); + g_free (upper); + } + else if (G_IS_PARAM_SPEC_UINT (spec)) + { + GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec); + + lower = describe_unsigned_constant (pspec->minimum); + upper = describe_unsigned_constant (pspec->maximum); + if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT) + desc = g_strdup (""); + else if (pspec->minimum == 0) + desc = g_strdup_printf ("<= %s", upper); + else if (pspec->maximum == G_MAXUINT) + desc = g_strdup_printf (">= %s", lower); + else + desc = g_strdup_printf ("[%s,%s]", lower, upper); + g_free (lower); + g_free (upper); + } + else if (G_IS_PARAM_SPEC_LONG (spec)) + { + GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec); + + lower = describe_signed_constant (pspec->minimum); + upper = describe_signed_constant (pspec->maximum); + if (pspec->minimum == G_MINLONG && pspec->maximum == G_MAXLONG) + desc = g_strdup (""); + else if (pspec->minimum == G_MINLONG) + desc = g_strdup_printf ("<= %s", upper); + else if (pspec->maximum == G_MAXLONG) + desc = g_strdup_printf (">= %s", lower); + else + desc = g_strdup_printf ("[%s,%s]", lower, upper); + g_free (lower); + g_free (upper); + } + else if (G_IS_PARAM_SPEC_ULONG (spec)) + { + GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec); + gchar *upper; + + lower = describe_unsigned_constant (pspec->minimum); + upper = describe_unsigned_constant (pspec->maximum); + if (pspec->minimum == 0 && pspec->maximum == G_MAXULONG) + desc = g_strdup (""); + else if (pspec->minimum == 0) + desc = g_strdup_printf ("<= %s", upper); + else if (pspec->maximum == G_MAXULONG) + desc = g_strdup_printf (">= %s", lower); + else + desc = g_strdup_printf ("[%s,%s]", lower, upper); + g_free (lower); + g_free (upper); + } + else if (G_IS_PARAM_SPEC_INT64 (spec)) + { + GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec); + + lower = describe_signed_constant (pspec->minimum); + upper = describe_signed_constant (pspec->maximum); + if (pspec->minimum == G_MININT64 && pspec->maximum == G_MAXINT64) + desc = g_strdup (""); + else if (pspec->minimum == G_MININT64) + desc = g_strdup_printf ("<= %s", upper); + else if (pspec->maximum == G_MAXINT64) + desc = g_strdup_printf (">= %s", lower); + else + desc = g_strdup_printf ("[%s,%s]", lower, upper); + g_free (lower); + g_free (upper); + } + else if (G_IS_PARAM_SPEC_UINT64 (spec)) + { + GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec); + + lower = describe_unsigned_constant (pspec->minimum); + upper = describe_unsigned_constant (pspec->maximum); + if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT64) + desc = g_strdup (""); + else if (pspec->minimum == 0) + desc = g_strdup_printf ("<= %s", upper); + else if (pspec->maximum == G_MAXUINT64) + desc = g_strdup_printf (">= %s", lower); + else + desc = g_strdup_printf ("[%s,%s]", lower, upper); + g_free (lower); + g_free (upper); + } + else if (G_IS_PARAM_SPEC_FLOAT (spec)) + { + GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec); + + lower = describe_double_constant (pspec->minimum); + upper = describe_double_constant (pspec->maximum); + if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXFLOAT)) + { + if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT)) + desc = g_strdup (""); + else + desc = g_strdup_printf ("<= %s", upper); + } + else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT)) + desc = g_strdup_printf (">= %s", lower); + else + desc = g_strdup_printf ("[%s,%s]", lower, upper); + g_free (lower); + g_free (upper); + } + else if (G_IS_PARAM_SPEC_DOUBLE (spec)) + { + GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec); + + lower = describe_double_constant (pspec->minimum); + upper = describe_double_constant (pspec->maximum); + if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXDOUBLE)) + { + if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE)) + desc = g_strdup (""); + else + desc = g_strdup_printf ("<= %s", upper); + } + else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE)) + desc = g_strdup_printf (">= %s", lower); + else + desc = g_strdup_printf ("[%s,%s]", lower, upper); + g_free (lower); + g_free (upper); + } + else + { + desc = g_strdup (""); + } + + return desc; +} + +static gchar* +describe_default (GParamSpec *spec) +{ + gchar *desc; + + if (G_IS_PARAM_SPEC_CHAR (spec)) + { + GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec); + + desc = g_strdup_printf ("%d", pspec->default_value); + } + else if (G_IS_PARAM_SPEC_UCHAR (spec)) + { + GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec); + + desc = g_strdup_printf ("%u", pspec->default_value); + } + else if (G_IS_PARAM_SPEC_BOOLEAN (spec)) + { + GParamSpecBoolean *pspec = G_PARAM_SPEC_BOOLEAN (spec); + + desc = g_strdup_printf ("%s", pspec->default_value ? "TRUE" : "FALSE"); + } + else if (G_IS_PARAM_SPEC_INT (spec)) + { + GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec); + + desc = g_strdup_printf ("%d", pspec->default_value); + } + else if (G_IS_PARAM_SPEC_UINT (spec)) + { + GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec); + + desc = g_strdup_printf ("%u", pspec->default_value); + } + else if (G_IS_PARAM_SPEC_LONG (spec)) + { + GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec); + + desc = g_strdup_printf ("%ld", pspec->default_value); + } + else if (G_IS_PARAM_SPEC_LONG (spec)) + { + GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec); + + desc = g_strdup_printf ("%lu", pspec->default_value); + } + else if (G_IS_PARAM_SPEC_INT64 (spec)) + { + GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec); + + desc = g_strdup_printf ("%" G_GINT64_FORMAT, pspec->default_value); + } + else if (G_IS_PARAM_SPEC_UINT64 (spec)) + { + GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec); + + desc = g_strdup_printf ("%" G_GUINT64_FORMAT, pspec->default_value); + } + else if (G_IS_PARAM_SPEC_UNICHAR (spec)) + { + GParamSpecUnichar *pspec = G_PARAM_SPEC_UNICHAR (spec); + + if (g_unichar_isprint (pspec->default_value)) + desc = g_strdup_printf ("'%c'", pspec->default_value); + else + desc = g_strdup_printf ("%u", pspec->default_value); + } + else if (G_IS_PARAM_SPEC_ENUM (spec)) + { + GParamSpecEnum *pspec = G_PARAM_SPEC_ENUM (spec); + + GEnumValue *value = g_enum_get_value (pspec->enum_class, pspec->default_value); + if (value) + desc = g_strdup_printf ("%s", value->value_name); + else + desc = g_strdup_printf ("%d", pspec->default_value); + } + else if (G_IS_PARAM_SPEC_FLAGS (spec)) + { + GParamSpecFlags *pspec = G_PARAM_SPEC_FLAGS (spec); + guint default_value; + GString *acc; + + default_value = pspec->default_value; + acc = g_string_new (""); + + while (default_value) + { + GFlagsValue *value = g_flags_get_first_value (pspec->flags_class, default_value); + + if (!value) + break; + + if (acc->len > 0) + g_string_append (acc, "|"); + g_string_append (acc, value->value_name); + + default_value &= ~value->value; + } + + if (default_value == 0) + desc = g_string_free (acc, FALSE); + else + { + desc = g_strdup_printf ("%d", pspec->default_value); + g_string_free (acc, TRUE); + } + } + else if (G_IS_PARAM_SPEC_FLOAT (spec)) + { + GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec); + + desc = g_strdup_printf ("%g", pspec->default_value); + } + else if (G_IS_PARAM_SPEC_DOUBLE (spec)) + { + GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec); + + desc = g_strdup_printf ("%lg", pspec->default_value); + } + else if (G_IS_PARAM_SPEC_STRING (spec)) + { + GParamSpecString *pspec = G_PARAM_SPEC_STRING (spec); + + if (pspec->default_value) + { + gchar *esc = g_strescape (pspec->default_value, NULL); + + desc = g_strdup_printf ("\\"%s\\"", esc); + + g_free (esc); + } + else + desc = g_strdup_printf ("NULL"); + } + else + { + desc = g_strdup (""); + } + + return desc; +} + + +static void +output_object_args (FILE *fp, GType object_type) +{ + gpointer class; + const gchar *object_class_name; + guint arg; + gchar flags[16], *pos; + GParamSpec **properties; + guint n_properties; + gboolean child_prop; + gboolean style_prop; + gboolean is_pointer; + const gchar *type_name; + gchar *type_desc; + gchar *default_value; + + if (G_TYPE_IS_OBJECT (object_type)) + { + class = g_type_class_peek (object_type); + if (!class) + return; + + properties = g_object_class_list_properties (class, &n_properties); + } +#if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 3) + else if (G_TYPE_IS_INTERFACE (object_type)) + { + class = g_type_default_interface_ref (object_type); + + if (!class) + return; + + properties = g_object_interface_list_properties (class, &n_properties); + } +#endif + else + return; + + object_class_name = g_type_name (object_type); + + child_prop = FALSE; + style_prop = FALSE; + + while (TRUE) { + qsort (properties, n_properties, sizeof (GParamSpec *), compare_param_specs); + for (arg = 0; arg < n_properties; arg++) + { + GParamSpec *spec = properties[arg]; + const gchar *nick, *blurb, *dot; + + if (spec->owner_type != object_type) + continue; + + pos = flags; + /* We use one-character flags for simplicity. */ + if (child_prop && !style_prop) + *pos++ = 'c'; + if (style_prop) + *pos++ = 's'; + if (spec->flags & G_PARAM_READABLE) + *pos++ = 'r'; + if (spec->flags & G_PARAM_WRITABLE) + *pos++ = 'w'; + if (spec->flags & G_PARAM_CONSTRUCT) + *pos++ = 'x'; + if (spec->flags & G_PARAM_CONSTRUCT_ONLY) + *pos++ = 'X'; + *pos = 0; + + nick = g_param_spec_get_nick (spec); + blurb = g_param_spec_get_blurb (spec); + + dot = ""; + if (blurb) { + int str_len = strlen (blurb); + if (str_len > 0 && blurb[str_len - 1] != '.') + dot = "."; + } + + type_desc = describe_type (spec); + default_value = describe_default (spec); + type_name = get_type_name (spec->value_type, &is_pointer); + fprintf (fp, "\\n%s::%s\\n%s%s\\n%s\\n%s\\n%s\\n%s%s\\n%s\\n\\n\\n", + object_class_name, g_param_spec_get_name (spec), type_name, is_pointer ? "*" : "", type_desc, flags, nick ? nick : "(null)", blurb ? blurb : "(null)", dot, default_value); + g_free (type_desc); + g_free (default_value); + } + + g_free (properties); + +#ifdef GTK_IS_CONTAINER_CLASS + if (!child_prop && GTK_IS_CONTAINER_CLASS (class)) { + properties = gtk_container_class_list_child_properties (class, &n_properties); + child_prop = TRUE; + continue; + } +#endif + +#ifdef GTK_IS_WIDGET_CLASS +#if GTK_CHECK_VERSION(2,1,0) + if (!style_prop && GTK_IS_WIDGET_CLASS (class)) { + properties = gtk_widget_class_list_style_properties (GTK_WIDGET_CLASS (class), &n_properties); + style_prop = TRUE; + continue; + } +#endif +#endif + + break; + } +} +EOT + +close OUTPUT; + +# Compile and run our file + +$CC = $ENV{CC} ? $ENV{CC} : "gcc"; +$LD = $ENV{LD} ? $ENV{LD} : $CC; +$CFLAGS = $ENV{CFLAGS} ? "$ENV{CFLAGS} -Wall -g" : "-Wall -g"; +$LDFLAGS = $ENV{LDFLAGS} ? $ENV{LDFLAGS} : ""; + +my $o_file; +if ($CC =~ /libtool/) { + $o_file = "$MODULE-scan.lo" +} else { + $o_file = "$MODULE-scan.o" +} + +print "gtk-doc: Compiling scanner\n"; +$command = "$CC $CFLAGS -c -o $o_file $MODULE-scan.c"; +system($command) == 0 or die "Compilation of scanner failed: $!\n"; + +print "gtk-doc: Linking scanner\n"; +$command = "$LD -o $MODULE-scan $o_file $LDFLAGS"; +system($command) == 0 or die "Linking of scanner failed: $!\n"; + +print "gtk-doc: Running scanner $MODULE-scan\n"; +system("sh -c ./$MODULE-scan") == 0 or die "Scan failed: $!\n"; + +unlink "./$MODULE-scan.c", "./$MODULE-scan.o", "./$MODULE-scan.lo", "./$MODULE-scan"; + +#&UpdateFileIfChanged ($old_signals_filename, $new_signals_filename, 0); +&UpdateFileIfChanged ($old_hierarchy_filename, $new_hierarchy_filename, 0); +&UpdateFileIfChanged ($old_interfaces_filename, $new_interfaces_filename, 0); +&UpdateFileIfChanged ($old_prerequisites_filename, $new_prerequisites_filename, 0); +#&UpdateFileIfChanged ($old_args_filename, $new_args_filename, 0); + + diff --git a/common/gtk-doc-plugins.mak b/common/gtk-doc-plugins.mak new file mode 100755 index 0000000..71f60ba --- /dev/null +++ b/common/gtk-doc-plugins.mak @@ -0,0 +1,397 @@ +# This is an include file specifically tuned for building documentation +# for GStreamer plug-ins + +help: + @echo + @echo "If you are a doc maintainer, run 'make update' to update" + @echo "the documentation files maintained in CVS" + @echo + @echo Other useful make targets: + @echo + @echo check-inspected-versions: make sure the inspected plugin info + @echo is up to date before a release + @echo + +# update the stuff maintained by doc maintainers +update: + $(MAKE) inspect-update + $(MAKE) scanobj-update + +# We set GPATH here; this gives us semantics for GNU make +# which are more like other make's VPATH, when it comes to +# whether a source that is a target of one rule is then +# searched for in VPATH/GPATH. +# +GPATH = $(srcdir) + +# thomas: make docs parallel installable +TARGET_DIR=$(HTML_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@ + +EXTRA_DIST = \ + scanobj-build.stamp \ + $(srcdir)/inspect/*.xml \ + inspect.stamp \ + inspect-build.stamp \ + $(SCANOBJ_FILES) \ + $(content_files) \ + $(extra_files) \ + $(HTML_IMAGES) \ + $(DOC_MAIN_SGML_FILE) \ + $(DOC_OVERRIDES) \ + $(DOC_MODULE)-sections.txt + +MAINTAINER_DOC_STAMPS = \ + scanobj-build.stamp \ + inspect-build.stamp \ + inspect.stamp + +# we don't add inspect-build.stamp and scanobj-build.stamp here since they are +# built manually by docs maintainers and result is commited to CVS +DOC_STAMPS = \ + scan-build.stamp \ + tmpl-build.stamp \ + sgml-build.stamp \ + html-build.stamp \ + scan.stamp \ + tmpl.stamp \ + sgml.stamp \ + html.stamp + +# files generated/updated by gtkdoc-scangobj +SCANOBJ_FILES = \ + $(DOC_MODULE).signals \ + $(DOC_MODULE).hierarchy \ + $(DOC_MODULE).interfaces \ + $(DOC_MODULE).prerequisites \ + $(DOC_MODULE).types \ + $(DOC_MODULE).args + +SCANOBJ_FILES_O = \ + .libs/$(DOC_MODULE)-scan.o + +# files generated/updated by gtkdoc-scan +SCAN_FILES = \ + $(DOC_MODULE)-sections.txt \ + $(DOC_MODULE)-overrides.txt \ + $(DOC_MODULE)-undocumented.txt \ + $(DOC_MODULE)-decl.txt \ + $(DOC_MODULE)-decl-list.txt + + +REPORT_FILES = \ + $(DOC_MODULE)-undocumented.txt \ + $(DOC_MODULE)-undeclared.txt \ + $(DOC_MODULE)-unused.txt + +# FC3 seems to need -scan.c to be part of CLEANFILES for distcheck +# no idea why FC4 can do without +CLEANFILES = \ + $(SCANOBJ_FILES_O) \ + $(DOC_MODULE)-scan.c \ + $(REPORT_FILES) \ + $(DOC_STAMPS) \ + inspect-registry.xml + + +if ENABLE_GTK_DOC +all-local: html-build.stamp + +#### scan gobjects; done by documentation maintainer #### +scanobj-update: + -rm scanobj-build.stamp + $(MAKE) scanobj-build.stamp + +# in the case of non-srcdir builds, the built gst directory gets added +# to gtk-doc scanning; but only then, to avoid duplicates +# FIXME: since we don't have the scan step as part of the build anymore, +# we could remove that +# TODO: finish elite script that updates the output files of this step +# instead of rewriting them, so that multiple maintainers can generate +# a collective set of args and signals +scanobj-build.stamp: $(SCANOBJ_DEPS) $(basefiles) + @echo '*** Scanning GObjects ***' + if test x"$(srcdir)" != x. ; then \ + for f in $(SCANOBJ_FILES); \ + do \ + cp $(srcdir)/$$f . ; \ + done; \ + else \ + $(INSPECT_ENVIRONMENT) \ + CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" \ + CFLAGS="-g $(GTKDOC_CFLAGS)" LDFLAGS="$(GTKDOC_LIBS)" \ + $(GST_DOC_SCANOBJ) --type-init-func="gst_init(NULL,NULL)" \ + --module=$(DOC_MODULE) --source=$(PACKAGE) && \ + $(PYTHON) \ + $(top_srcdir)/common/scangobj-merge.py $(DOC_MODULE); \ + fi + touch scanobj-build.stamp + +$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(SCANOBJ_FILES_O): scan-build.stamp + @true + +### inspect GStreamer plug-ins; done by documentation maintainer ### + +# only look at the plugins in this module when building inspect .xml stuff +INSPECT_REGISTRY=$(top_builddir)/docs/plugins/inspect-registry.xml +INSPECT_ENVIRONMENT=\ + GST_PLUGIN_SYSTEM_PATH= \ + GST_PLUGIN_PATH=$(top_builddir)/gst:$(top_builddir)/sys:$(top_builddir)/ext:$(top_builddir)/plugins:$(top_builddir)/src \ + GST_REGISTRY=$(INSPECT_REGISTRY) + +# update the element and plugin XML descriptions; store in inspect/ +inspect: + mkdir inspect + +inspect-update: inspect + -rm $(INSPECT_REGISTRY) + -rm inspect-build.stamp + $(MAKE) inspect-build.stamp + +# FIXME: inspect.stamp should be written to by gst-xmlinspect.py +# IF the output changed; see gtkdoc-mktmpl +inspect-build.stamp: + @echo '*** Rebuilding plugin inspection files ***' + if test x"$(srcdir)" != x. ; then \ + cp $(srcdir)/inspect.stamp . ; \ + cp $(srcdir)/inspect-build.stamp . ; \ + else \ + $(INSPECT_ENVIRONMENT) $(PYTHON) \ + $(top_srcdir)/common/gst-xmlinspect.py $(PACKAGE) inspect && \ + echo -n "timestamp" > inspect.stamp && \ + touch inspect-build.stamp; \ + fi + +### scan headers; done on every build ### +scan-build.stamp: $(HFILE_GLOB) $(EXTRA_HFILES) $(basefiles) scanobj-build.stamp inspect-build.stamp + if test "x$(top_srcdir)" != "x$(top_builddir)" && \ + test -d "$(top_builddir)/gst"; \ + then \ + export BUILT_OPTIONS="--source-dir=$(top_builddir)/gst"; \ + fi; \ + gtkdoc-scan \ + $(SCAN_OPTIONS) $(EXTRA_HFILES) \ + --module=$(DOC_MODULE) \ + $$BUILT_OPTIONS \ + --ignore-headers="$(IGNORE_HFILES)"; \ + touch scan-build.stamp + +#### update templates; done on every build #### + +### FIXME: make this error out again when docs are fixed for 0.9 +# in a non-srcdir build, we need to copy files from the previous step +# and the files from previous runs of this step +tmpl-build.stamp: $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_OVERRIDES) + @echo '*** Rebuilding template files ***' + if test x"$(srcdir)" != x. ; then \ + for f in $(SCANOBJ_FILES) $(SCAN_FILES); \ + do \ + if test -e $(srcdir)/$$f; then cp $(srcdir)/$$f . ; fi; \ + done; \ + fi + gtkdoc-mktmpl --module=$(DOC_MODULE) | tee tmpl-build.log + $(PYTHON) \ + $(top_srcdir)/common/mangle-tmpl.py $(srcdir)/inspect tmpl + @cat $(DOC_MODULE)-unused.txt + rm -f tmpl-build.log + touch tmpl-build.stamp + +tmpl.stamp: tmpl-build.stamp + @true + +#### build xml; done on every build #### + +### FIXME: make this error out again when docs are fixed for 0.9 +sgml-build.stamp: tmpl.stamp inspect.stamp $(CFILE_GLOB) $(top_srcdir)/common/plugins.xsl + @echo '*** Building XML ***' + @-mkdir -p xml + @for a in $(srcdir)/inspect/*.xml; do \ + xsltproc --stringparam module $(MODULE) \ + $(top_srcdir)/common/plugins.xsl $$a > xml/`basename $$a`; done + @for f in $(EXAMPLE_CFILES); do \ + $(PYTHON) $(top_srcdir)/common/c-to-xml.py $$f > xml/element-`basename $$f .c`.xml; done + gtkdoc-mkdb \ + --module=$(DOC_MODULE) \ + --source-dir=$(DOC_SOURCE_DIR) \ + --main-sgml-file=$(srcdir)/$(DOC_MAIN_SGML_FILE) \ + --output-format=xml \ + --ignore-files="$(IGNORE_HFILES) $(IGNORE_CFILES)" \ + $(MKDB_OPTIONS) \ + | tee sgml-build.log + @if grep "WARNING:" sgml-build.log > /dev/null; then true; fi # exit 1; fi + cp ../version.entities xml + rm sgml-build.log + touch sgml-build.stamp + +sgml.stamp: sgml-build.stamp + @true + +#### build html; done on every step #### + +html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) + @echo '*** Building HTML ***' + if test -d html; then rm -rf html; fi + mkdir html + cp $(srcdir)/$(DOC_MAIN_SGML_FILE) html + @for f in $(content_files); do cp $(srcdir)/$$f html; done + cp -pr xml html + cp ../version.entities html + cd html && gtkdoc-mkhtml $(DOC_MODULE) $(DOC_MAIN_SGML_FILE) \ + 2>&1 | tee ../html-build.log + @if grep "warning:" html-build.log > /dev/null; then \ + echo "ERROR"; grep "warning:" html-build.log; exit 1; fi + @rm html-build.log + mv html/index.sgml html/index.sgml.bak + $(SED) "s/ href=\"$(DOC_MODULE)\// href=\"$(DOC_MODULE)-@GST_MAJORMINOR@\//g" html/index.sgml.bak >html/index.sgml + rm -f html/index.sgml.bak + rm -f html/$(DOC_MAIN_SGML_FILE) + rm -rf html/xml + rm -f html/version.entities + test "x$(HTML_IMAGES)" = "x" || for i in "" $(HTML_IMAGES) ; do \ + if test "$$i" != ""; then cp $(srcdir)/$$i html ; fi; done + @echo '-- Fixing Crossreferences' + gtkdoc-fixxref --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS) + touch html-build.stamp +else +all-local: +endif + +# FIXME: these rules need a little cleaning up +clean-local: + rm -f *~ *.bak + rm -rf .libs +# clean files generated for tmpl build + -rm -rf tmpl +# clean files copied/generated for nonsrcdir tmpl build + if test x"$(srcdir)" != x. ; then \ + rm -rf $(SCANOBJ_FILES) $(SCAN_FILES); \ + fi +# clean files generated for xml build + -rm -rf xml +# clean files generate for html build + -rm -rf html + +distclean-local: clean + rm -rf tmpl/*.sgml.bak + rm -f *.stamp || true + rm -rf *.o + +# thomas: make docs parallel installable; devhelp requires majorminor too +install-data-local: + $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR) + (installfiles=`echo ./html/*.html`; \ + if test "$$installfiles" = './html/*.html'; \ + then echo '-- Nothing to install' ; \ + else \ + for i in $$installfiles; do \ + echo '-- Installing '$$i ; \ + $(INSTALL_DATA) $$i $(DESTDIR)$(TARGET_DIR); \ + done; \ + pngfiles=`echo ./html/*.png`; \ + if test "$$pngfiles" != './html/*.png'; then \ + for i in $$pngfiles; do \ + echo '-- Installing '$$i ; \ + $(INSTALL_DATA) $$i $(DESTDIR)$(TARGET_DIR); \ + done; \ + fi; \ + echo '-- Installing $(srcdir)/html/$(DOC_MODULE).devhelp' ; \ + $(INSTALL_DATA) $(srcdir)/html/$(DOC_MODULE).devhelp \ + $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp; \ + if test -e $(srcdir)/html/$(DOC_MODULE).devhelp2; then \ + $(INSTALL_DATA) $(srcdir)/html/$(DOC_MODULE).devhelp2 \ + $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp2; \ + fi; \ + echo '-- Installing $(srcdir)/html/index.sgml' ; \ + $(INSTALL_DATA) $(srcdir)/html/index.sgml $(DESTDIR)$(TARGET_DIR); \ + if test -e $(srcdir)/html/style.css; then \ + echo '-- Installing $(srcdir)/html/style.css' ; \ + $(INSTALL_DATA) $(srcdir)/html/style.css $(DESTDIR)$(TARGET_DIR); \ + fi; \ + fi) +uninstall-local: + (installfiles=`echo ./html/*.html`; \ + if test "$$installfiles" = './html/*.html'; \ + then echo '-- Nothing to uninstall' ; \ + else \ + for i in $$installfiles; do \ + rmfile=`basename $$i` ; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/'$$rmfile ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/$$rmfile; \ + done; \ + pngfiles=`echo ./html/*.png`; \ + if test "$$pngfiles" != './html/*.png'; then \ + for i in $$pngfiles; do \ + rmfile=`basename $$i` ; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/'$$rmfile ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/$$rmfile; \ + done; \ + fi; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE).devhelp' ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp; \ + if test -e $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp2; then \ + rm -f $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp2; \ + fi; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/index.sgml' ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/index.sgml; \ + if test -e $(DESTDIR)$(TARGET_DIR)/style.css; then \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/style.css' ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/style.css; \ + fi; \ + fi) + if test -d $(DESTDIR)$(TARGET_DIR); then rmdir -p --ignore-fail-on-non-empty $(DESTDIR)$(TARGET_DIR) 2>/dev/null; fi; true + +# +# Checks +# +check-hierarchy: $(DOC_MODULE).hierarchy + @if grep ' ' $(DOC_MODULE).hierarchy; then \ + echo "$(DOC_MODULE).hierarchy contains tabs, please fix"; \ + /bin/false; \ + fi + +check: check-hierarchy + +# wildcard is apparently not portable to other makes, hence the use of find +inspect_files = $(shell find $(top_srcdir)/docs/plugins/inspect -name '*.xml') + +check-inspected-versions: + @echo Checking plugin versions of inspected plugin data ...; \ + fail=0 ; \ + for each in $(inspect_files) ; do \ + if (grep -H '' $$each | grep -v '$(VERSION)'); then \ + echo $$each should be fixed to say version $(VERSION) or be removed ; \ + echo "sed -i -e 's//$(VERSION)<\/version>/'" $$each; \ + echo ; \ + fail=1; \ + fi ; \ + done ; \ + exit $$fail + +# +# Require gtk-doc when making dist +# +if ENABLE_GTK_DOC +dist-check-gtkdoc: +else +dist-check-gtkdoc: + @echo "*** gtk-doc must be installed and enabled in order to make dist" + @false +endif + +# FIXME: decide whether we want to dist generated html or not +dist-hook: dist-check-gtkdoc dist-hook-local + mkdir $(distdir)/tmpl + mkdir $(distdir)/xml + mkdir $(distdir)/html + -cp $(srcdir)/tmpl/*.sgml $(distdir)/tmpl + -cp $(srcdir)/sgml/*.xml $(distdir)/xml + -cp $(srcdir)/html/index.sgml $(distdir)/html + -cp $(srcdir)/html/*.html $(srcdir)/html/*.css $(distdir)/html + -cp $(srcdir)/html/$(DOC_MODULE).devhelp* $(distdir)/html + + images=$(HTML_IMAGES) ; \ + for i in "" $$images ; do \ + if test "$$i" != ""; then cp $(srcdir)/$$i $(distdir)/html ; fi; \ + done + +.PHONY : dist-hook-local + diff --git a/common/gtk-doc.mak b/common/gtk-doc.mak new file mode 100755 index 0000000..1c9ece1 --- /dev/null +++ b/common/gtk-doc.mak @@ -0,0 +1,267 @@ +########################################################################### +# Everything below here is generic and you shouldn't need to change it. +########################################################################### +# thomas: except of course that we did + +# thomas: copied from glib-2 +# We set GPATH here; this gives us semantics for GNU make +# which are more like other make's VPATH, when it comes to +# whether a source that is a target of one rule is then +# searched for in VPATH/GPATH. +# +GPATH = $(srcdir) + +# thomas: make docs parallel installable +TARGET_DIR=$(HTML_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@ + +EXTRA_DIST = \ + $(content_files) \ + $(extra_files) \ + $(HTML_IMAGES) \ + $(DOC_MAIN_SGML_FILE) \ + $(DOC_MODULE).types \ + $(DOC_OVERRIDES) \ + $(DOC_MODULE)-sections.txt + +DOC_STAMPS = \ + scan-build.stamp \ + tmpl-build.stamp \ + sgml-build.stamp \ + html-build.stamp \ + $(srcdir)/tmpl.stamp \ + $(srcdir)/sgml.stamp \ + $(srcdir)/html.stamp + +SCANOBJ_FILES = \ + $(DOC_MODULE).args \ + $(DOC_MODULE).hierarchy \ + $(DOC_MODULE).interfaces \ + $(DOC_MODULE).prerequisites \ + .libs/$(DOC_MODULE)-scan.o \ + $(DOC_MODULE).signals + +REPORT_FILES = \ + $(DOC_MODULE)-undocumented.txt \ + $(DOC_MODULE)-undeclared.txt \ + $(DOC_MODULE)-unused.txt + +CLEANFILES = $(SCANOBJ_FILES) $(REPORT_FILES) $(DOC_STAMPS) + +if ENABLE_GTK_DOC +all-local: html-build.stamp + +#### scan #### + +# in the case of non-srcdir builds, the built gst directory gets added +# to gtk-doc scanning; but only then, to avoid duplicates +scan-build.stamp: $(HFILE_GLOB) $(SCANOBJ_DEPS) $(basefiles) + @echo '*** Scanning header files ***' + if grep -l '^..*$$' $(srcdir)/$(DOC_MODULE).types > /dev/null; \ + then \ + if test x"$(srcdir)" != x. ; then \ + cp $(srcdir)/$(DOC_MODULE).types . ; \ + chmod u+w $(DOC_MODULE).types ; \ + fi ; \ + GST_PLUGIN_SYSTEM_PATH=`cd $(top_builddir) && pwd` \ + GST_PLUGIN_PATH= \ + CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" \ + CFLAGS="$(GTKDOC_CFLAGS)" LDFLAGS="$(GTKDOC_LIBS)" \ + gtkdoc-scangobj --type-init-func="gst_init(NULL,NULL)" \ + --module=$(DOC_MODULE) ; \ + else \ + cd $(srcdir) ; \ + for i in $(SCANOBJ_FILES) ; do \ + test -f $$i || touch $$i ; \ + done \ + fi + if test "x$(top_srcdir)" != "x$(top_builddir)"; \ + then \ + export BUILT_OPTIONS="--source-dir=$(DOC_BUILD_DIR)"; \ + fi; \ + gtkdoc-scan \ + $(SCAN_OPTIONS) $(EXTRA_HFILES) \ + --module=$(DOC_MODULE) \ + --source-dir=$(DOC_SOURCE_DIR) \ + $$BUILT_OPTIONS \ + --ignore-headers="$(IGNORE_HFILES)" + touch scan-build.stamp + +$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES): scan-build.stamp + @true + +#### templates #### + +tmpl-build.stamp: $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_OVERRIDES) + @echo '*** Rebuilding template files ***' + if test x"$(srcdir)" != x. ; then \ + cp $(srcdir)/$(DOC_MODULE)-sections.txt . ; \ + touch $(DOC_MODULE)-decl.txt ; \ + fi + gtkdoc-mktmpl --module=$(DOC_MODULE) | tee tmpl-build.log + @if test -s $(DOC_MODULE)-unused.txt; then \ + exit $(if $(DOCS_ARE_INCOMPLETE_PLEASE_FIXME),0,1); fi + rm -f tmpl-build.log + touch tmpl-build.stamp + +tmpl.stamp: tmpl-build.stamp + @true + +#### xml #### + +### FIXME: make this error out again when docs are complete +sgml-build.stamp: tmpl.stamp $(CFILE_GLOB) + @echo '*** Building XML ***' + gtkdoc-mkdb --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --main-sgml-file=$(srcdir)/$(DOC_MAIN_SGML_FILE) --output-format=xml $(MKDB_OPTIONS) | tee sgml-build.log + @if grep "WARNING:" sgml-build.log > /dev/null; then true; fi # exit 1; fi + rm sgml-build.log + touch sgml-build.stamp + +sgml.stamp: sgml-build.stamp + @true + +#### html #### + +html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) + @echo '*** Building HTML ***' + if test -d html; then rm -rf html; fi + mkdir html + cp $(srcdir)/$(DOC_MAIN_SGML_FILE) html + @for f in $(content_files); do cp $(srcdir)/$$f html; done + cp -pr xml html + cp ../version.entities html + cd html && gtkdoc-mkhtml $(DOC_MODULE) $(DOC_MAIN_SGML_FILE) + mv html/index.sgml html/index.sgml.bak + $(SED) "s/ href=\"$(DOC_MODULE)\// href=\"$(DOC_MODULE)-@GST_MAJORMINOR@\//g" html/index.sgml.bak >html/index.sgml + rm -f html/index.sgml.bak + rm -f html/$(DOC_MAIN_SGML_FILE) + rm -rf html/xml + rm -f html/version.entities + test "x$(HTML_IMAGES)" = "x" || for i in "" $(HTML_IMAGES) ; do \ + if test "$$i" != ""; then cp $(srcdir)/$$i html ; fi; done + @echo '-- Fixing Crossreferences' + gtkdoc-fixxref --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS) + touch html-build.stamp +else +all-local: +endif + +clean-local: + rm -f *~ *.bak + rm -rf xml html + rm -rf .libs + +maintainer-clean-local: clean + cd $(srcdir) && rm -rf xml html $(DOC_MODULE)-decl-list.txt $(DOC_MODULE)-decl.txt + +# company: don't delete .sgml and -sections.txt as they're in CVS +# FIXME : thomas added all sgml files and some other things to make +# make distcheck work +distclean-local: clean + rm -f $(DOC_MODULE)-decl-list.txt + rm -f $(DOC_MODULE)-decl.txt + rm -f $(REPORT_FILES) + rm -rf tmpl/*.sgml.bak + rm -f $(DOC_MODULE).hierarchy + rm -f *.stamp || true + if test x"$(srcdir)" != x. ; then \ + rm -f $(DOC_MODULE)-docs.sgml ; \ + rm -f $(DOC_MODULE).types ; \ + rm -f $(DOC_MODULE).interfaces ; \ + rm -f $(DOC_MODULE)-overrides.txt ; \ + rm -f $(DOC_MODULE).prerequisites ; \ + rm -f $(DOC_MODULE)-sections.txt ; \ + rm -rf tmpl/*.sgml ; \ + fi + rm -rf *.o + +# thomas: make docs parallel installable; devhelp requires majorminor too +install-data-local: + $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR) + (installfiles=`echo ./html/*.html`; \ + if test "$$installfiles" = './html/*.html'; \ + then echo '-- Nothing to install' ; \ + else \ + for i in $$installfiles; do \ + echo '-- Installing '$$i ; \ + $(INSTALL_DATA) $$i $(DESTDIR)$(TARGET_DIR); \ + done; \ + pngfiles=`echo ./html/*.png`; \ + if test "$$pngfiles" != './html/*.png'; then \ + for i in $$pngfiles; do \ + echo '-- Installing '$$i ; \ + $(INSTALL_DATA) $$i $(DESTDIR)$(TARGET_DIR); \ + done; \ + fi; \ + echo '-- Installing $(srcdir)/html/$(DOC_MODULE).devhelp' ; \ + $(INSTALL_DATA) $(srcdir)/html/$(DOC_MODULE).devhelp \ + $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp; \ + if test -e $(srcdir)/html/$(DOC_MODULE).devhelp2; then \ + $(INSTALL_DATA) $(srcdir)/html/$(DOC_MODULE).devhelp2 \ + $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp2; \ + fi; \ + echo '-- Installing $(srcdir)/html/index.sgml' ; \ + $(INSTALL_DATA) $(srcdir)/html/index.sgml $(DESTDIR)$(TARGET_DIR); \ + if test -e $(srcdir)/html/style.css; then \ + echo '-- Installing $(srcdir)/html/style.css' ; \ + $(INSTALL_DATA) $(srcdir)/html/style.css $(DESTDIR)$(TARGET_DIR); \ + fi; \ + fi) +uninstall-local: + (installfiles=`echo ./html/*.html`; \ + if test "$$installfiles" = './html/*.html'; \ + then echo '-- Nothing to uninstall' ; \ + else \ + for i in $$installfiles; do \ + rmfile=`basename $$i` ; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/'$$rmfile ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/$$rmfile; \ + done; \ + pngfiles=`echo ./html/*.png`; \ + if test "$$pngfiles" != './html/*.png'; then \ + for i in $$pngfiles; do \ + rmfile=`basename $$i` ; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/'$$rmfile ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/$$rmfile; \ + done; \ + fi; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE).devhelp' ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp; \ + if test -e $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp2; then \ + rm -f $(DESTDIR)$(TARGET_DIR)/$(DOC_MODULE)-@GST_MAJORMINOR@.devhelp2; \ + fi; \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/index.sgml' ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/index.sgml; \ + if test -e $(DESTDIR)$(TARGET_DIR)/style.css; then \ + echo '-- Uninstalling $(DESTDIR)$(TARGET_DIR)/style.css' ; \ + rm -f $(DESTDIR)$(TARGET_DIR)/style.css; \ + fi; \ + fi) + if test -d $(DESTDIR)$(TARGET_DIR); then rmdir -p --ignore-fail-on-non-empty $(DESTDIR)$(TARGET_DIR) 2>/dev/null; fi; true + +# +# Require gtk-doc when making dist +# +if ENABLE_GTK_DOC +dist-check-gtkdoc: +else +dist-check-gtkdoc: + @echo "*** gtk-doc must be installed and enabled in order to make dist" + @false +endif + +dist-hook: dist-check-gtkdoc dist-hook-local + mkdir $(distdir)/tmpl + mkdir $(distdir)/xml + mkdir $(distdir)/html + -cp $(srcdir)/tmpl/*.sgml $(distdir)/tmpl + -cp $(srcdir)/sgml/*.xml $(distdir)/xml + -cp $(srcdir)/html/index.sgml $(distdir)/html + -cp $(srcdir)/html/*.html $(srcdir)/html/*.css $(distdir)/html + -cp $(srcdir)/html/$(DOC_MODULE).devhelp* $(distdir)/html + + images=$(HTML_IMAGES) ; \ + for i in "" $$images ; do \ + if test "$$i" != ""; then cp $(srcdir)/$$i $(distdir)/html ; fi; \ + done + +.PHONY : dist-hook-local diff --git a/common/m4/Makefile.am b/common/m4/Makefile.am new file mode 100644 index 0000000..99ead5c --- /dev/null +++ b/common/m4/Makefile.am @@ -0,0 +1,29 @@ +EXTRA_DIST = \ + README \ + as-ac-expand.m4 \ + as-auto-alt.m4 \ + as-compiler-flag.m4 \ + as-compiler.m4 \ + as-docbook.m4 \ + as-gcc-inline-assembly.m4 \ + as-libtool.m4 \ + as-libtool-tags.m4 \ + as-python.m4 \ + as-scrub-include.m4 \ + as-version.m4 \ + ax_create_stdint_h.m4 \ + glib-gettext.m4 \ + gst-arch.m4 \ + gst-args.m4 \ + gst-check.m4 \ + gst-debuginfo.m4 \ + gst-default.m4 \ + gst-doc.m4 \ + gst-feature.m4 \ + gst-function.m4 \ + gst-gettext.m4 \ + gst-glib2.m4 \ + gst-libxml2.m4 \ + gst-plugindir.m4 \ + gst-valgrind.m4 \ + pkg.m4 diff --git a/common/m4/README b/common/m4/README new file mode 100755 index 0000000..f044598 --- /dev/null +++ b/common/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/common/m4/as-ac-expand.m4 b/common/m4/as-ac-expand.m4 new file mode 100755 index 0000000..d6c9e33 --- /dev/null +++ b/common/m4/as-ac-expand.m4 @@ -0,0 +1,43 @@ +dnl as-ac-expand.m4 0.2.0 +dnl autostars m4 macro for expanding directories using configure's prefix +dnl thomas@apestaart.org + +dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR) +dnl example +dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir) +dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local + +AC_DEFUN([AS_AC_EXPAND], +[ + EXP_VAR=[$1] + FROM_VAR=[$2] + + dnl first expand prefix and exec_prefix if necessary + prefix_save=$prefix + exec_prefix_save=$exec_prefix + + dnl if no prefix given, then use /usr/local, the default prefix + if test "x$prefix" = "xNONE"; then + prefix="$ac_default_prefix" + fi + dnl if no exec_prefix given, then use prefix + if test "x$exec_prefix" = "xNONE"; then + exec_prefix=$prefix + fi + + full_var="$FROM_VAR" + dnl loop until it doesn't change anymore + while true; do + new_full_var="`eval echo $full_var`" + if test "x$new_full_var" = "x$full_var"; then break; fi + full_var=$new_full_var + done + + dnl clean up + full_var=$new_full_var + AC_SUBST([$1], "$full_var") + + dnl restore prefix and exec_prefix + prefix=$prefix_save + exec_prefix=$exec_prefix_save +]) diff --git a/common/m4/as-auto-alt.m4 b/common/m4/as-auto-alt.m4 new file mode 100755 index 0000000..3f7920d --- /dev/null +++ b/common/m4/as-auto-alt.m4 @@ -0,0 +1,50 @@ +dnl as-auto-alt.m4 0.0.2 +dnl autostars m4 macro for supplying alternate autotools versions to configure +dnl thomas@apestaart.org +dnl +dnl AS_AUTOTOOLS_ALTERNATE() +dnl +dnl supplies --with arguments for autoconf, autoheader, automake, aclocal + +AC_DEFUN([AS_AUTOTOOLS_ALTERNATE], +[ + dnl allow for different autoconf version + AC_ARG_WITH(autoconf, + AC_HELP_STRING([--with-autoconf], + [use a different autoconf for regeneration of Makefiles]), + [ + unset AUTOCONF + AM_MISSING_PROG(AUTOCONF, ${withval}) + AC_MSG_NOTICE([Using $AUTOCONF as autoconf]) + ]) + + dnl allow for different autoheader version + AC_ARG_WITH(autoheader, + AC_HELP_STRING([--with-autoheader], + [use a different autoheader for regeneration of Makefiles]), + [ + unset AUTOHEADER + AM_MISSING_PROG(AUTOHEADER, ${withval}) + AC_MSG_NOTICE([Using $AUTOHEADER as autoheader]) + ]) + + dnl allow for different automake version + AC_ARG_WITH(automake, + AC_HELP_STRING([--with-automake], + [use a different automake for regeneration of Makefiles]), + [ + unset AUTOMAKE + AM_MISSING_PROG(AUTOMAKE, ${withval}) + AC_MSG_NOTICE([Using $AUTOMAKE as automake]) + ]) + + dnl allow for different aclocal version + AC_ARG_WITH(aclocal, + AC_HELP_STRING([--with-aclocal], + [use a different aclocal for regeneration of Makefiles]), + [ + unset ACLOCAL + AM_MISSING_PROG(ACLOCAL, ${withval}) + AC_MSG_NOTICE([Using $ACLOCAL as aclocal]) + ]) +]) diff --git a/common/m4/as-compiler-flag.m4 b/common/m4/as-compiler-flag.m4 new file mode 100755 index 0000000..882a4c7 --- /dev/null +++ b/common/m4/as-compiler-flag.m4 @@ -0,0 +1,64 @@ +dnl as-compiler-flag.m4 0.1.0 + +dnl autostars m4 macro for detection of compiler flags + +dnl David Schleef +dnl Tim-Philipp Müller + +dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) +dnl Tries to compile with the given CFLAGS. +dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, +dnl and ACTION-IF-NOT-ACCEPTED otherwise. + +AC_DEFUN([AS_COMPILER_FLAG], +[ + AC_MSG_CHECKING([to see if compiler understands $1]) + + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $1" + + AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) + CFLAGS="$save_CFLAGS" + + if test "X$flag_ok" = Xyes ; then + $2 + true + else + $3 + true + fi + AC_MSG_RESULT([$flag_ok]) +]) + +dnl AS_CXX_COMPILER_FLAG(CPPFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) +dnl Tries to compile with the given CPPFLAGS. +dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, +dnl and ACTION-IF-NOT-ACCEPTED otherwise. + +AC_DEFUN([AS_CXX_COMPILER_FLAG], +[ + AC_REQUIRE([AC_PROG_CXX]) + + AC_MSG_CHECKING([to see if c++ compiler understands $1]) + + save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $1" + + AC_LANG_PUSH(C++) + + AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) + CPPFLAGS="$save_CPPFLAGS" + + if test "X$flag_ok" = Xyes ; then + $2 + true + else + $3 + true + fi + + AC_LANG_POP(C++) + + AC_MSG_RESULT([$flag_ok]) +]) + diff --git a/common/m4/as-compiler.m4 b/common/m4/as-compiler.m4 new file mode 100755 index 0000000..233a719 --- /dev/null +++ b/common/m4/as-compiler.m4 @@ -0,0 +1,44 @@ +dnl as-compiler.m4 0.1.0 + +dnl autostars m4 macro for detection of compiler flavor + +dnl Thomas Vander Stichele + +dnl $Id: as-compiler.m4,v 1.4 2004/06/01 09:33:45 thomasvs Exp $ + +dnl AS_COMPILER(COMPILER) +dnl will set variable COMPILER to +dnl - gcc +dnl - forte +dnl - (empty) if no guess could be made + +AC_DEFUN([AS_COMPILER], +[ + as_compiler= + AC_MSG_CHECKING(for compiler flavour) + + dnl is it gcc ? + if test "x$GCC" = "xyes"; then + as_compiler="gcc" + fi + + dnl is it forte ? + AC_TRY_RUN([ +int main +(int argc, char *argv[]) +{ +#ifdef __sun + return 0; +#else + return 1; +#endif +} + ], as_compiler="forte", ,) + + if test "x$as_compiler" = "x"; then + AC_MSG_RESULT([unknown !]) + else + AC_MSG_RESULT($as_compiler) + fi + [$1]=$as_compiler +]) diff --git a/common/m4/as-docbook.m4 b/common/m4/as-docbook.m4 new file mode 100755 index 0000000..8a1b32a --- /dev/null +++ b/common/m4/as-docbook.m4 @@ -0,0 +1,66 @@ +dnl AS_DOCBOOK([, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl checks if xsltproc can build docbook documentation +dnl (which is possible if the catalog is set up properly +dnl I also tried checking for a specific version and type of docbook +dnl but xsltproc seemed to happily run anyway, so we can't check for that +dnl and version +dnl this macro takes inspiration from +dnl http://www.movement.uklinux.net/docs/docbook-autotools/configure.html +AC_DEFUN([AS_DOCBOOK], +[ + XSLTPROC_FLAGS=--nonet + DOCBOOK_ROOT= + TYPE_LC=xml + TYPE_UC=XML + DOCBOOK_VERSION=4.1.2 + + if test ! -f /etc/xml/catalog; then + for i in /usr/share/sgml/docbook/stylesheet/xsl/nwalsh /usr/share/sgml/docbook/xsl-stylesheets/ /usr/local/share/xsl/docbook ; + do + if test -d "$i"; then + DOCBOOK_ROOT=$i + fi + done + else + XML_CATALOG=/etc/xml/catalog + CAT_ENTRY_START='' + fi + + dnl We need xsltproc to process the test + AC_CHECK_PROG(XSLTPROC,xsltproc,xsltproc,) + XSLTPROC_WORKS=no + if test -n "$XSLTPROC"; then + AC_MSG_CHECKING([whether xsltproc docbook processing works]) + + if test -n "$XML_CATALOG"; then + DB_FILE="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl" + else + DB_FILE="$DOCBOOK_ROOT/xhtml/docbook.xsl" + fi + $XSLTPROC $XSLTPROC_FLAGS $DB_FILE >/dev/null 2>&1 << END + + + + +END + if test "$?" = 0; then + XSLTPROC_WORKS=yes + fi + AC_MSG_RESULT($XSLTPROC_WORKS) + fi + + if test "x$XSLTPROC_WORKS" = "xyes"; then + dnl execute ACTION-IF-FOUND + ifelse([$1], , :, [$1]) + else + dnl execute ACTION-IF-NOT-FOUND + ifelse([$2], , :, [$2]) + fi + + AC_SUBST(XML_CATALOG) + AC_SUBST(XSLTPROC_FLAGS) + AC_SUBST(DOCBOOK_ROOT) + AC_SUBST(CAT_ENTRY_START) + AC_SUBST(CAT_ENTRY_END) +]) diff --git a/common/m4/as-gcc-inline-assembly.m4 b/common/m4/as-gcc-inline-assembly.m4 new file mode 100755 index 0000000..799e80e --- /dev/null +++ b/common/m4/as-gcc-inline-assembly.m4 @@ -0,0 +1,52 @@ +dnl as-gcc-inline-assembly.m4 0.1.0 + +dnl autostars m4 macro for detection of gcc inline assembly + +dnl David Schleef + +dnl $Id: as-gcc-inline-assembly.m4,v 1.1 2008-02-26 09:38:00 thaytan Exp $ + +dnl AS_COMPILER_FLAG(ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) +dnl Tries to compile with the given CFLAGS. +dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, +dnl and ACTION-IF-NOT-ACCEPTED otherwise. + +AC_DEFUN([AS_GCC_INLINE_ASSEMBLY], +[ + AC_MSG_CHECKING([if compiler supports gcc-style inline assembly]) + + AC_TRY_COMPILE([], [ +#ifdef __GNUC_MINOR__ +#if (__GNUC__ * 1000 + __GNUC_MINOR__) < 3004 +#error GCC before 3.4 has critical bugs compiling inline assembly +#endif +#endif +__asm__ (""::) ], [flag_ok=yes], [flag_ok=no]) + + if test "X$flag_ok" = Xyes ; then + $1 + true + else + $2 + true + fi + AC_MSG_RESULT([$flag_ok]) +]) + + +AC_DEFUN([AS_GCC_ASM_POWERPC_FPU], +[ + AC_MSG_CHECKING([if compiler supports FPU instructions on PowerPC]) + + AC_TRY_COMPILE([], [__asm__ ("fadd 0,0,0"::) ], [flag_ok=yes], [flag_ok=no]) + + if test "X$flag_ok" = Xyes ; then + $1 + true + else + $2 + true + fi + AC_MSG_RESULT([$flag_ok]) +]) + diff --git a/common/m4/as-libtool-tags.m4 b/common/m4/as-libtool-tags.m4 new file mode 100755 index 0000000..c522ff2 --- /dev/null +++ b/common/m4/as-libtool-tags.m4 @@ -0,0 +1,83 @@ +dnl as-libtool-tags.m4 0.1.4 + +dnl autostars m4 macro for selecting libtool "tags" (languages) + +dnl Andy Wingo does not claim credit for this macro +dnl backported from libtool 1.6 by Paolo Bonzini +dnl see http://lists.gnu.org/archive/html/libtool/2003-12/msg00007.html + +dnl $Id: as-libtool-tags.m4,v 1.3 2006-04-01 15:30:56 thomasvs Exp $ + +dnl AS_LIBTOOL_TAGS([tags...]) + +dnl example +dnl AS_LIBTOOL_TAGS([]) for only C (no fortran, etc) + +dnl When AC_LIBTOOL_TAGS is used, I redefine _LT_AC_TAGCONFIG +dnl to be more similar to the libtool 1.6 implementation, which +dnl uses an m4 loop and m4 case instead of a shell loop. This +dnl way the CXX/GCJ/F77/RC tests are not always expanded. + +dnl AS_LIBTOOL_TAGS +dnl --------------- +dnl tags to enable +AC_DEFUN([AS_LIBTOOL_TAGS], +[m4_define([_LT_TAGS],[$1]) +m4_define([_LT_AC_TAGCONFIG], [ + # redefined LT AC TAGCONFIG + if test -f "$ltmain"; then + if test ! -f "${ofile}"; then + AC_MSG_WARN([output file `$ofile' does not exist]) + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) + else + AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) + fi + fi + + AC_FOREACH([_LT_TAG], _LT_TAGS, + echo THOMAS: tag _LT_TAG + [m4_case(_LT_TAG, + [CXX], [ + if test -n "$CXX" && test "X$CXX" != "Xno"; then + echo "THOMAS: YAY CXX" + AC_LIBTOOL_LANG_CXX_CONFIG + available_tags="$available_tags _LT_TAG" + fi], + [F77], [ + if test -n "$F77" && test "X$F77" != "Xno"; then + AC_LIBTOOL_LANG_F77_CONFIG + available_tags="$available_tags _LT_TAG" + fi], + [GCJ], [ + if test -n "$GCJ" && test "X$GCJ" != "Xno"; then + AC_LIBTOOL_LANG_GCJ_CONFIG + available_tags="$available_tags _LT_TAG" + fi], + [RC], [ + if test -n "$RC" && test "X$RC" != "Xno"; then + AC_LIBTOOL_LANG_RC_CONFIG + available_tags="$available_tags _LT_TAG" + fi], + [m4_errprintn(m4_location[: error: invalid tag name: ]"_LT_TAG") + m4_exit(1)]) + ]) + echo THOMAS: available tags: $available_tags + fi + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + AC_MSG_NOTICE([updated available libtool tags with $available_tags.]) + else + rm -f "${ofile}T" + AC_MSG_ERROR([unable to update list of available tagged configurations.]) + + fi + +])dnl _LT_AC_TAG_CONFIG +]) diff --git a/common/m4/as-libtool.m4 b/common/m4/as-libtool.m4 new file mode 100755 index 0000000..73dec1f --- /dev/null +++ b/common/m4/as-libtool.m4 @@ -0,0 +1,45 @@ +dnl as-libtool.m4 0.1.4 + +dnl autostars m4 macro for libtool versioning + +dnl Thomas Vander Stichele + +dnl $Id: as-libtool.m4,v 1.6 2004/06/01 10:04:44 thomasvs Exp $ + +dnl AS_LIBTOOL(PREFIX, CURRENT, REVISION, AGE, [RELEASE]) + +dnl example +dnl AS_LIBTOOL(GST, 2, 0, 0) + +dnl this macro +dnl - defines [$PREFIX]_CURRENT, REVISION and AGE +dnl - defines [$PREFIX]_LIBVERSION +dnl - defines [$PREFIX]_LT_LDFLAGS to set versioning +dnl - AC_SUBST's them all + +dnl if RELEASE is given, then add a -release option to the LDFLAGS +dnl with the given release version +dnl then use [$PREFIX]_LT_LDFLAGS in the relevant Makefile.am's + +dnl call AM_PROG_LIBTOOL after this call + +AC_DEFUN([AS_LIBTOOL], +[ + [$1]_CURRENT=[$2] + [$1]_REVISION=[$3] + [$1]_AGE=[$4] + [$1]_LIBVERSION=[$2]:[$3]:[$4] + AC_SUBST([$1]_CURRENT) + AC_SUBST([$1]_REVISION) + AC_SUBST([$1]_AGE) + AC_SUBST([$1]_LIBVERSION) + + [$1]_LT_LDFLAGS="$[$1]_LT_LDFLAGS -version-info $[$1]_LIBVERSION" + if test ! -z "[$5]" + then + [$1]_LT_LDFLAGS="$[$1]_LT_LDFLAGS -release [$5]" + fi + AC_SUBST([$1]_LT_LDFLAGS) + + AC_LIBTOOL_DLOPEN +]) diff --git a/common/m4/as-python.m4 b/common/m4/as-python.m4 new file mode 100755 index 0000000..eb9b175 --- /dev/null +++ b/common/m4/as-python.m4 @@ -0,0 +1,152 @@ +## ------------------------ +## Python file handling +## From Andrew Dalke +## Updated by James Henstridge +## Updated by Andy Wingo to loop through possible pythons +## ------------------------ + +# AS_PATH_PYTHON([MINIMUM-VERSION]) + +# Adds support for distributing Python modules and packages. To +# install modules, copy them to $(pythondir), using the python_PYTHON +# automake variable. To install a package with the same name as the +# automake package, install to $(pkgpythondir), or use the +# pkgpython_PYTHON automake variable. + +# The variables $(pyexecdir) and $(pkgpyexecdir) are provided as +# locations to install python extension modules (shared libraries). +# Another macro is required to find the appropriate flags to compile +# extension modules. + +# If your package is configured with a different prefix to python, +# users will have to add the install directory to the PYTHONPATH +# environment variable, or create a .pth file (see the python +# documentation for details). + +# If the MINIMUM-VERSION argument is passed, AS_PATH_PYTHON will +# cause an error if the version of python installed on the system +# doesn't meet the requirement. MINIMUM-VERSION should consist of +# numbers and dots only. + +# Updated to loop over all possible python binaries by Andy Wingo +# +# Updated to only warn and unset PYTHON if no good one is found + +AC_DEFUN([AS_PATH_PYTHON], + [ + dnl Find a version of Python. I could check for python versions 1.4 + dnl or earlier, but the default installation locations changed from + dnl $prefix/lib/site-python in 1.4 to $prefix/lib/python1.5/site-packages + dnl in 1.5, and I don't want to maintain that logic. + + dnl should we do the version check? + PYTHON_CANDIDATES="python python2.2 python2.1 python2.0 python2 \ + python1.6 python1.5" + ifelse([$1],[], + [AC_PATH_PROG(PYTHON, $PYTHON_CANDIDATES)], + [ + AC_MSG_NOTICE(Looking for Python version >= $1) + changequote(<<, >>)dnl + prog=" +import sys, string +minver = '$1' +# split string by '.' and convert to numeric +minver_info = map(string.atoi, string.split(minver, '.')) +# we can now do comparisons on the two lists: +if sys.version_info >= tuple(minver_info): + sys.exit(0) +else: + sys.exit(1)" + changequote([, ])dnl + + python_good=false + for python_candidate in $PYTHON_CANDIDATES; do + unset PYTHON + AC_PATH_PROG(PYTHON, $python_candidate) 1> /dev/null 2> /dev/null + + if test "x$PYTHON" = "x"; then continue; fi + + if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC; then + AC_MSG_CHECKING(["$PYTHON":]) + AC_MSG_RESULT([okay]) + python_good=true + break; + else + dnl clear the cache val + unset ac_cv_path_PYTHON + fi + done + ]) + + if test "$python_good" != "true"; then + AC_MSG_WARN([No suitable version of python found]) + PYTHON= + else + + AC_MSG_CHECKING([local Python configuration]) + + dnl Query Python for its version number. Getting [:3] seems to be + dnl the best way to do this; it's what "site.py" does in the standard + dnl library. Need to change quote character because of [:3] + + AC_SUBST(PYTHON_VERSION) + changequote(<<, >>)dnl + PYTHON_VERSION=`$PYTHON -c "import sys; print sys.version[:3]"` + changequote([, ])dnl + + + dnl Use the values of $prefix and $exec_prefix for the corresponding + dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made + dnl distinct variables so they can be overridden if need be. However, + dnl general consensus is that you shouldn't need this ability. + + AC_SUBST(PYTHON_PREFIX) + PYTHON_PREFIX='${prefix}' + + AC_SUBST(PYTHON_EXEC_PREFIX) + PYTHON_EXEC_PREFIX='${exec_prefix}' + + dnl At times (like when building shared libraries) you may want + dnl to know which OS platform Python thinks this is. + + AC_SUBST(PYTHON_PLATFORM) + PYTHON_PLATFORM=`$PYTHON -c "import sys; print sys.platform"` + + + dnl Set up 4 directories: + + dnl pythondir -- where to install python scripts. This is the + dnl site-packages directory, not the python standard library + dnl directory like in previous automake betas. This behaviour + dnl is more consistent with lispdir.m4 for example. + dnl + dnl Also, if the package prefix isn't the same as python's prefix, + dnl then the old $(pythondir) was pretty useless. + + AC_SUBST(pythondir) + pythondir=$PYTHON_PREFIX"/lib/python"$PYTHON_VERSION/site-packages + + dnl pkgpythondir -- $PACKAGE directory under pythondir. Was + dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is + dnl more consistent with the rest of automake. + dnl Maybe this should be put in python.am? + + AC_SUBST(pkgpythondir) + pkgpythondir=\${pythondir}/$PACKAGE + + dnl pyexecdir -- directory for installing python extension modules + dnl (shared libraries) Was PYTHON_SITE_EXEC in previous betas. + + AC_SUBST(pyexecdir) + pyexecdir=$PYTHON_EXEC_PREFIX"/lib/python"$PYTHON_VERSION/site-packages + + dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE) + dnl Maybe this should be put in python.am? + + AC_SUBST(pkgpyexecdir) + pkgpyexecdir=\${pyexecdir}/$PACKAGE + + AC_MSG_RESULT([looks good]) + + fi +]) diff --git a/common/m4/as-scrub-include.m4 b/common/m4/as-scrub-include.m4 new file mode 100755 index 0000000..96dfb8f --- /dev/null +++ b/common/m4/as-scrub-include.m4 @@ -0,0 +1,36 @@ +dnl as-scrub-include.m4 0.0.4 + +dnl autostars m4 macro for scrubbing CFLAGS of system include dirs +dnl because gcc 3.x complains about including system including dirs + +dnl Thomas Vander Stichele + +dnl $Id: as-scrub-include.m4,v 1.5 2004/06/12 08:19:09 thomasvs Exp $ + +dnl This macro uses output of cpp -v and expects it to contain text that +dnl looks a little bit like this: +dnl #include <...> search starts here: +dnl /usr/local/include +dnl /usr/lib/gcc-lib/i386-redhat-linux/3.2/include +dnl /usr/include +dnl End of search list. + +dnl AS_SCRUB_INCLUDE(VAR) +dnl example +dnl AS_SCRUB_INCLUDE(CFLAGS) +dnl will remove all system include dirs from the given CFLAGS + +AC_DEFUN([AS_SCRUB_INCLUDE], +[ + GIVEN_CFLAGS=$[$1] + INCLUDE_DIRS=`echo | cpp -v 2>&1` + + dnl remove everything from this output between the "starts here" and "End of" + dnl line + INCLUDE_DIRS=`echo $INCLUDE_DIRS | sed -e 's/.*<...> search starts here://' | sed -e 's/End of search list.*//'` + for dir in $INCLUDE_DIRS; do + dnl use "" as the sed script so $dir gets expanded + GIVEN_CFLAGS=`echo $GIVEN_CFLAGS | sed -e "s#-I$dir ##"` + done + [$1]=$GIVEN_CFLAGS +]) diff --git a/common/m4/as-version.m4 b/common/m4/as-version.m4 new file mode 100755 index 0000000..a5b4399 --- /dev/null +++ b/common/m4/as-version.m4 @@ -0,0 +1,71 @@ +dnl as-version.m4 0.2.0 + +dnl autostars m4 macro for versioning + +dnl Thomas Vander Stichele + +dnl $Id: as-version.m4,v 1.4 2004/06/01 09:40:05 thomasvs Exp $ + +dnl AS_VERSION + +dnl example +dnl AS_VERSION + +dnl this macro +dnl - AC_SUBST's PACKAGE_VERSION_MAJOR, _MINOR, _MICRO +dnl - AC_SUBST's PACKAGE_VERSION_RELEASE, +dnl which can be used for rpm release fields +dnl - doesn't call AM_INIT_AUTOMAKE anymore because it prevents +dnl maintainer mode from running correctly +dnl +dnl don't forget to put #undef PACKAGE_VERSION_RELEASE in acconfig.h +dnl if you use acconfig.h + +AC_DEFUN([AS_VERSION], +[ + PACKAGE_VERSION_MAJOR=$(echo AC_PACKAGE_VERSION | cut -d'.' -f1) + PACKAGE_VERSION_MINOR=$(echo AC_PACKAGE_VERSION | cut -d'.' -f2) + PACKAGE_VERSION_MICRO=$(echo AC_PACKAGE_VERSION | cut -d'.' -f3) + + AC_SUBST(PACKAGE_VERSION_MAJOR) + AC_SUBST(PACKAGE_VERSION_MINOR) + AC_SUBST(PACKAGE_VERSION_MICRO) +]) + +dnl AS_NANO(ACTION-IF-NO-NANO, [ACTION-IF-NANO]) + +dnl requires AC_INIT to be called before +dnl For projects using a fourth or nano number in your versioning to indicate +dnl development or prerelease snapshots, this macro allows the build to be +dnl set up differently accordingly. + +dnl this macro: +dnl - parses AC_PACKAGE_VERSION, set by AC_INIT, and extracts the nano number +dnl - sets the variable PACKAGE_VERSION_NANO +dnl - sets the variable PACKAGE_VERSION_RELEASE, which can be used +dnl for rpm release fields +dnl - executes ACTION-IF-NO-NANO or ACTION-IF-NANO + +dnl example: +dnl AS_NANO(RELEASE="yes", RELEASE="no") + +AC_DEFUN([AS_NANO], +[ + AC_MSG_CHECKING(nano version) + + NANO=$(echo AC_PACKAGE_VERSION | cut -d'.' -f4) + + if test x"$NANO" = x || test "x$NANO" = "x0" ; then + AC_MSG_RESULT([0 (release)]) + NANO=0 + PACKAGE_VERSION_RELEASE=1 + ifelse([$1], , :, [$1]) + else + AC_MSG_RESULT($NANO) + PACKAGE_VERSION_RELEASE=0.`date +%Y%m%d.%H%M%S` + ifelse([$2], , :, [$2]) + fi + PACKAGE_VERSION_NANO=$NANO + AC_SUBST(PACKAGE_VERSION_NANO) + AC_SUBST(PACKAGE_VERSION_RELEASE) +]) diff --git a/common/m4/ax_create_stdint_h.m4 b/common/m4/ax_create_stdint_h.m4 new file mode 100755 index 0000000..13bf699 --- /dev/null +++ b/common/m4/ax_create_stdint_h.m4 @@ -0,0 +1,734 @@ +##### http://autoconf-archive.cryp.to/ax_create_stdint_h.html +# +# SYNOPSIS +# +# AX_CREATE_STDINT_H [( HEADER-TO-GENERATE [, HEDERS-TO-CHECK])] +# +# DESCRIPTION +# +# the "ISO C9X: 7.18 Integer types " section requires the +# existence of an include file that defines a set of +# typedefs, especially uint8_t,int32_t,uintptr_t. Many older +# installations will not provide this file, but some will have the +# very same definitions in . In other enviroments we can +# use the inet-types in which would define the typedefs +# int8_t and u_int8_t respectivly. +# +# This macros will create a local "_stdint.h" or the headerfile given +# as an argument. In many cases that file will just "#include +# " or "#include ", while in other environments +# it will provide the set of basic 'stdint's definitions/typedefs: +# +# int8_t,uint8_t,int16_t,uint16_t,int32_t,uint32_t,intptr_t,uintptr_t +# int_least32_t.. int_fast32_t.. intmax_t +# +# which may or may not rely on the definitions of other files, or +# using the AC_CHECK_SIZEOF macro to determine the actual sizeof each +# type. +# +# if your header files require the stdint-types you will want to +# create an installable file mylib-int.h that all your other +# installable header may include. So if you have a library package +# named "mylib", just use +# +# AX_CREATE_STDINT_H(mylib-int.h) +# +# in configure.ac and go to install that very header file in +# Makefile.am along with the other headers (mylib.h) - and the +# mylib-specific headers can simply use "#include " to +# obtain the stdint-types. +# +# Remember, if the system already had a valid , the +# generated file will include it directly. No need for fuzzy +# HAVE_STDINT_H things... (oops, GCC 4.2.x has deliberatly disabled +# its stdint.h for non-c99 compilation and the c99-mode is not the +# default. Therefore this macro will not use the compiler's stdint.h +# - please complain to the GCC developers). +# +# LAST MODIFICATION +# +# 2007-06-27 +# +# COPYLEFT +# +# Copyright (c) 2007 Guido U. Draheim +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. +# +# As a special exception, the respective Autoconf Macro's copyright +# owner gives unlimited permission to copy, distribute and modify the +# configure scripts that are the output of Autoconf when processing +# the Macro. You need not follow the terms of the GNU General Public +# License when using or distributing such scripts, even though +# portions of the text of the Macro appear in them. The GNU General +# Public License (GPL) does govern all other use of the material that +# constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the +# Autoconf Macro released by the Autoconf Macro Archive. When you +# make and distribute a modified version of the Autoconf Macro, you +# may extend this special exception to the GPL to apply to your +# modified version as well. + +AC_DEFUN([AX_CHECK_DATA_MODEL],[ + AC_CHECK_SIZEOF(char) + AC_CHECK_SIZEOF(short) + AC_CHECK_SIZEOF(int) + AC_CHECK_SIZEOF(long) + AC_CHECK_SIZEOF(void*) + ac_cv_char_data_model="" + ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_char" + ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_short" + ac_cv_char_data_model="$ac_cv_char_data_model$ac_cv_sizeof_int" + ac_cv_long_data_model="" + ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_int" + ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_long" + ac_cv_long_data_model="$ac_cv_long_data_model$ac_cv_sizeof_voidp" + AC_MSG_CHECKING([data model]) + case "$ac_cv_char_data_model/$ac_cv_long_data_model" in + 122/242) ac_cv_data_model="IP16" ; n="standard 16bit machine" ;; + 122/244) ac_cv_data_model="LP32" ; n="standard 32bit machine" ;; + 122/*) ac_cv_data_model="i16" ; n="unusual int16 model" ;; + 124/444) ac_cv_data_model="ILP32" ; n="standard 32bit unixish" ;; + 124/488) ac_cv_data_model="LP64" ; n="standard 64bit unixish" ;; + 124/448) ac_cv_data_model="LLP64" ; n="unusual 64bit unixish" ;; + 124/*) ac_cv_data_model="i32" ; n="unusual int32 model" ;; + 128/888) ac_cv_data_model="ILP64" ; n="unusual 64bit numeric" ;; + 128/*) ac_cv_data_model="i64" ; n="unusual int64 model" ;; + 222/*2) ac_cv_data_model="DSP16" ; n="strict 16bit dsptype" ;; + 333/*3) ac_cv_data_model="DSP24" ; n="strict 24bit dsptype" ;; + 444/*4) ac_cv_data_model="DSP32" ; n="strict 32bit dsptype" ;; + 666/*6) ac_cv_data_model="DSP48" ; n="strict 48bit dsptype" ;; + 888/*8) ac_cv_data_model="DSP64" ; n="strict 64bit dsptype" ;; + 222/*|333/*|444/*|666/*|888/*) : + ac_cv_data_model="iDSP" ; n="unusual dsptype" ;; + *) ac_cv_data_model="none" ; n="very unusual model" ;; + esac + AC_MSG_RESULT([$ac_cv_data_model ($ac_cv_long_data_model, $n)]) +]) + +dnl AX_CHECK_HEADER_STDINT_X([HEADERLIST][,ACTION-IF]) +AC_DEFUN([AX_CHECK_HEADER_STDINT_X],[ +AC_CACHE_CHECK([for stdint uintptr_t], [ac_cv_header_stdint_x],[ + ac_cv_header_stdint_x="" # the 1997 typedefs (inttypes.h) + AC_MSG_RESULT([(..)]) + for i in m4_ifval([$1],[$1],[stdint.h inttypes.h sys/inttypes.h sys/types.h]) + do + unset ac_cv_type_uintptr_t + unset ac_cv_type_uint64_t + AC_CHECK_TYPE(uintptr_t,[ac_cv_header_stdint_x=$i],continue,[#include <$i>]) + AC_CHECK_TYPE(uint64_t,[and64="/uint64_t"],[and64=""],[#include<$i>]) + m4_ifvaln([$2],[$2]) break + done + AC_MSG_CHECKING([for stdint uintptr_t]) + ]) +]) + +AC_DEFUN([AX_CHECK_HEADER_STDINT_O],[ +AC_CACHE_CHECK([for stdint uint32_t], [ac_cv_header_stdint_o],[ + ac_cv_header_stdint_o="" # the 1995 typedefs (sys/inttypes.h) + AC_MSG_RESULT([(..)]) + for i in m4_ifval([$1],[$1],[inttypes.h sys/inttypes.h sys/types.h stdint.h]) + do + unset ac_cv_type_uint32_t + unset ac_cv_type_uint64_t + AC_CHECK_TYPE(uint32_t,[ac_cv_header_stdint_o=$i],continue,[#include <$i>]) + AC_CHECK_TYPE(uint64_t,[and64="/uint64_t"],[and64=""],[#include<$i>]) + m4_ifvaln([$2],[$2]) break + break; + done + AC_MSG_CHECKING([for stdint uint32_t]) + ]) +]) + +AC_DEFUN([AX_CHECK_HEADER_STDINT_U],[ +AC_CACHE_CHECK([for stdint u_int32_t], [ac_cv_header_stdint_u],[ + ac_cv_header_stdint_u="" # the BSD typedefs (sys/types.h) + AC_MSG_RESULT([(..)]) + for i in m4_ifval([$1],[$1],[sys/types.h inttypes.h sys/inttypes.h]) ; do + unset ac_cv_type_u_int32_t + unset ac_cv_type_u_int64_t + AC_CHECK_TYPE(u_int32_t,[ac_cv_header_stdint_u=$i],continue,[#include <$i>]) + AC_CHECK_TYPE(u_int64_t,[and64="/u_int64_t"],[and64=""],[#include<$i>]) + m4_ifvaln([$2],[$2]) break + break; + done + AC_MSG_CHECKING([for stdint u_int32_t]) + ]) +]) + +AC_DEFUN([AX_CREATE_STDINT_H], +[# ------ AX CREATE STDINT H ------------------------------------- +AC_MSG_CHECKING([for stdint types]) +ac_stdint_h=`echo ifelse($1, , _stdint.h, $1)` +# try to shortcircuit - if the default include path of the compiler +# can find a "stdint.h" header then we assume that all compilers can. +AC_CACHE_VAL([ac_cv_header_stdint_t],[ +old_CXXFLAGS="$CXXFLAGS" ; CXXFLAGS="" +old_CPPFLAGS="$CPPFLAGS" ; CPPFLAGS="" +old_CFLAGS="$CFLAGS" ; CFLAGS="" +AC_TRY_COMPILE([#include ],[int_least32_t v = 0;], +[ac_cv_stdint_result="(assuming C99 compatible system)" + ac_cv_header_stdint_t="stdint.h"; ], +[ac_cv_header_stdint_t=""]) +if test "$GCC" = "yes" && test ".$ac_cv_header_stdint_t" = "."; then +CFLAGS="-std=c99" +AC_TRY_COMPILE([#include ],[int_least32_t v = 0;], +[AC_MSG_WARN(your GCC compiler has a defunct stdint.h for its default-mode)]) +fi +CXXFLAGS="$old_CXXFLAGS" +CPPFLAGS="$old_CPPFLAGS" +CFLAGS="$old_CFLAGS" ]) + +v="... $ac_cv_header_stdint_h" +if test "$ac_stdint_h" = "stdint.h" ; then + AC_MSG_RESULT([(are you sure you want them in ./stdint.h?)]) +elif test "$ac_stdint_h" = "inttypes.h" ; then + AC_MSG_RESULT([(are you sure you want them in ./inttypes.h?)]) +elif test "_$ac_cv_header_stdint_t" = "_" ; then + AC_MSG_RESULT([(putting them into $ac_stdint_h)$v]) +else + ac_cv_header_stdint="$ac_cv_header_stdint_t" + AC_MSG_RESULT([$ac_cv_header_stdint (shortcircuit)]) +fi + +if test "_$ac_cv_header_stdint_t" = "_" ; then # can not shortcircuit.. + +dnl .....intro message done, now do a few system checks..... +dnl btw, all old CHECK_TYPE macros do automatically "DEFINE" a type, +dnl therefore we use the autoconf implementation detail CHECK_TYPE_NEW +dnl instead that is triggered with 3 or more arguments (see types.m4) + +inttype_headers=`echo $2 | sed -e 's/,/ /g'` + +ac_cv_stdint_result="(no helpful system typedefs seen)" +AX_CHECK_HEADER_STDINT_X(dnl + stdint.h inttypes.h sys/inttypes.h $inttype_headers, + ac_cv_stdint_result="(seen uintptr_t$and64 in $i)") + +if test "_$ac_cv_header_stdint_x" = "_" ; then +AX_CHECK_HEADER_STDINT_O(dnl, + inttypes.h sys/inttypes.h stdint.h $inttype_headers, + ac_cv_stdint_result="(seen uint32_t$and64 in $i)") +fi + +if test "_$ac_cv_header_stdint_x" = "_" ; then +if test "_$ac_cv_header_stdint_o" = "_" ; then +AX_CHECK_HEADER_STDINT_U(dnl, + sys/types.h inttypes.h sys/inttypes.h $inttype_headers, + ac_cv_stdint_result="(seen u_int32_t$and64 in $i)") +fi fi + +dnl if there was no good C99 header file, do some typedef checks... +if test "_$ac_cv_header_stdint_x" = "_" ; then + AC_MSG_CHECKING([for stdint datatype model]) + AC_MSG_RESULT([(..)]) + AX_CHECK_DATA_MODEL +fi + +if test "_$ac_cv_header_stdint_x" != "_" ; then + ac_cv_header_stdint="$ac_cv_header_stdint_x" +elif test "_$ac_cv_header_stdint_o" != "_" ; then + ac_cv_header_stdint="$ac_cv_header_stdint_o" +elif test "_$ac_cv_header_stdint_u" != "_" ; then + ac_cv_header_stdint="$ac_cv_header_stdint_u" +else + ac_cv_header_stdint="stddef.h" +fi + +AC_MSG_CHECKING([for extra inttypes in chosen header]) +AC_MSG_RESULT([($ac_cv_header_stdint)]) +dnl see if int_least and int_fast types are present in _this_ header. +unset ac_cv_type_int_least32_t +unset ac_cv_type_int_fast32_t +AC_CHECK_TYPE(int_least32_t,,,[#include <$ac_cv_header_stdint>]) +AC_CHECK_TYPE(int_fast32_t,,,[#include<$ac_cv_header_stdint>]) +AC_CHECK_TYPE(intmax_t,,,[#include <$ac_cv_header_stdint>]) + +fi # shortcircut to system "stdint.h" +# ------------------ PREPARE VARIABLES ------------------------------ +if test "$GCC" = "yes" ; then +ac_cv_stdint_message="using gnu compiler "`$CC --version | head -1` +else +ac_cv_stdint_message="using $CC" +fi + +AC_MSG_RESULT([make use of $ac_cv_header_stdint in $ac_stdint_h dnl +$ac_cv_stdint_result]) + +dnl ----------------------------------------------------------------- +# ----------------- DONE inttypes.h checks START header ------------- +AC_CONFIG_COMMANDS([$ac_stdint_h],[ +AC_MSG_NOTICE(creating $ac_stdint_h : $_ac_stdint_h) +ac_stdint=$tmp/_stdint.h + +echo "#ifndef" $_ac_stdint_h >$ac_stdint +echo "#define" $_ac_stdint_h "1" >>$ac_stdint +echo "#ifndef" _GENERATED_STDINT_H >>$ac_stdint +echo "#define" _GENERATED_STDINT_H '"'$PACKAGE $VERSION'"' >>$ac_stdint +echo "/* generated $ac_cv_stdint_message */" >>$ac_stdint +if test "_$ac_cv_header_stdint_t" != "_" ; then +echo "#define _STDINT_HAVE_STDINT_H" "1" >>$ac_stdint +echo "#include " >>$ac_stdint +echo "#endif" >>$ac_stdint +echo "#endif" >>$ac_stdint +else + +cat >>$ac_stdint < +#else +#include + +/* .................... configured part ............................ */ + +STDINT_EOF + +echo "/* whether we have a C99 compatible stdint header file */" >>$ac_stdint +if test "_$ac_cv_header_stdint_x" != "_" ; then + ac_header="$ac_cv_header_stdint_x" + echo "#define _STDINT_HEADER_INTPTR" '"'"$ac_header"'"' >>$ac_stdint +else + echo "/* #undef _STDINT_HEADER_INTPTR */" >>$ac_stdint +fi + +echo "/* whether we have a C96 compatible inttypes header file */" >>$ac_stdint +if test "_$ac_cv_header_stdint_o" != "_" ; then + ac_header="$ac_cv_header_stdint_o" + echo "#define _STDINT_HEADER_UINT32" '"'"$ac_header"'"' >>$ac_stdint +else + echo "/* #undef _STDINT_HEADER_UINT32 */" >>$ac_stdint +fi + +echo "/* whether we have a BSD compatible inet types header */" >>$ac_stdint +if test "_$ac_cv_header_stdint_u" != "_" ; then + ac_header="$ac_cv_header_stdint_u" + echo "#define _STDINT_HEADER_U_INT32" '"'"$ac_header"'"' >>$ac_stdint +else + echo "/* #undef _STDINT_HEADER_U_INT32 */" >>$ac_stdint +fi + +echo "" >>$ac_stdint + +if test "_$ac_header" != "_" ; then if test "$ac_header" != "stddef.h" ; then + echo "#include <$ac_header>" >>$ac_stdint + echo "" >>$ac_stdint +fi fi + +echo "/* which 64bit typedef has been found */" >>$ac_stdint +if test "$ac_cv_type_uint64_t" = "yes" ; then +echo "#define _STDINT_HAVE_UINT64_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_UINT64_T */" >>$ac_stdint +fi +if test "$ac_cv_type_u_int64_t" = "yes" ; then +echo "#define _STDINT_HAVE_U_INT64_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_U_INT64_T */" >>$ac_stdint +fi +echo "" >>$ac_stdint + +echo "/* which type model has been detected */" >>$ac_stdint +if test "_$ac_cv_char_data_model" != "_" ; then +echo "#define _STDINT_CHAR_MODEL" "$ac_cv_char_data_model" >>$ac_stdint +echo "#define _STDINT_LONG_MODEL" "$ac_cv_long_data_model" >>$ac_stdint +else +echo "/* #undef _STDINT_CHAR_MODEL // skipped */" >>$ac_stdint +echo "/* #undef _STDINT_LONG_MODEL // skipped */" >>$ac_stdint +fi +echo "" >>$ac_stdint + +echo "/* whether int_least types were detected */" >>$ac_stdint +if test "$ac_cv_type_int_least32_t" = "yes"; then +echo "#define _STDINT_HAVE_INT_LEAST32_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_INT_LEAST32_T */" >>$ac_stdint +fi +echo "/* whether int_fast types were detected */" >>$ac_stdint +if test "$ac_cv_type_int_fast32_t" = "yes"; then +echo "#define _STDINT_HAVE_INT_FAST32_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_INT_FAST32_T */" >>$ac_stdint +fi +echo "/* whether intmax_t type was detected */" >>$ac_stdint +if test "$ac_cv_type_intmax_t" = "yes"; then +echo "#define _STDINT_HAVE_INTMAX_T" "1" >>$ac_stdint +else +echo "/* #undef _STDINT_HAVE_INTMAX_T */" >>$ac_stdint +fi +echo "" >>$ac_stdint + + cat >>$ac_stdint <= 199901L +#define _HAVE_UINT64_T +#define _HAVE_LONGLONG_UINT64_T +typedef long long int64_t; +typedef unsigned long long uint64_t; + +#elif !defined __STRICT_ANSI__ +#if defined _MSC_VER || defined __WATCOMC__ || defined __BORLANDC__ +#define _HAVE_UINT64_T +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; + +#elif defined __GNUC__ || defined __MWERKS__ || defined __ELF__ +/* note: all ELF-systems seem to have loff-support which needs 64-bit */ +#if !defined _NO_LONGLONG +#define _HAVE_UINT64_T +#define _HAVE_LONGLONG_UINT64_T +typedef long long int64_t; +typedef unsigned long long uint64_t; +#endif + +#elif defined __alpha || (defined __mips && defined _ABIN32) +#if !defined _NO_LONGLONG +typedef long int64_t; +typedef unsigned long uint64_t; +#endif + /* compiler/cpu type to define int64_t */ +#endif +#endif +#endif + +#if defined _STDINT_HAVE_U_INT_TYPES +/* int8_t int16_t int32_t defined by inet code, redeclare the u_intXX types */ +typedef u_int8_t uint8_t; +typedef u_int16_t uint16_t; +typedef u_int32_t uint32_t; + +/* glibc compatibility */ +#ifndef __int8_t_defined +#define __int8_t_defined +#endif +#endif + +#ifdef _STDINT_NEED_INT_MODEL_T +/* we must guess all the basic types. Apart from byte-adressable system, */ +/* there a few 32-bit-only dsp-systems that we guard with BYTE_MODEL 8-} */ +/* (btw, those nibble-addressable systems are way off, or so we assume) */ + +dnl /* have a look at "64bit and data size neutrality" at */ +dnl /* http://unix.org/version2/whatsnew/login_64bit.html */ +dnl /* (the shorthand "ILP" types always have a "P" part) */ + +#if defined _STDINT_BYTE_MODEL +#if _STDINT_LONG_MODEL+0 == 242 +/* 2:4:2 = IP16 = a normal 16-bit system */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; +#ifndef __int8_t_defined +#define __int8_t_defined +typedef char int8_t; +typedef short int16_t; +typedef long int32_t; +#endif +#elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL == 444 +/* 2:4:4 = LP32 = a 32-bit system derived from a 16-bit */ +/* 4:4:4 = ILP32 = a normal 32-bit system */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#ifndef __int8_t_defined +#define __int8_t_defined +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +#endif +#elif _STDINT_LONG_MODEL+0 == 484 || _STDINT_LONG_MODEL+0 == 488 +/* 4:8:4 = IP32 = a 32-bit system prepared for 64-bit */ +/* 4:8:8 = LP64 = a normal 64-bit system */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#ifndef __int8_t_defined +#define __int8_t_defined +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +#endif +/* this system has a "long" of 64bit */ +#ifndef _HAVE_UINT64_T +#define _HAVE_UINT64_T +typedef unsigned long uint64_t; +typedef long int64_t; +#endif +#elif _STDINT_LONG_MODEL+0 == 448 +/* LLP64 a 64-bit system derived from a 32-bit system */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#ifndef __int8_t_defined +#define __int8_t_defined +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +#endif +/* assuming the system has a "long long" */ +#ifndef _HAVE_UINT64_T +#define _HAVE_UINT64_T +#define _HAVE_LONGLONG_UINT64_T +typedef unsigned long long uint64_t; +typedef long long int64_t; +#endif +#else +#define _STDINT_NO_INT32_T +#endif +#else +#define _STDINT_NO_INT8_T +#define _STDINT_NO_INT32_T +#endif +#endif + +/* + * quote from SunOS-5.8 sys/inttypes.h: + * Use at your own risk. As of February 1996, the committee is squarely + * behind the fixed sized types; the "least" and "fast" types are still being + * discussed. The probability that the "fast" types may be removed before + * the standard is finalized is high enough that they are not currently + * implemented. + */ + +#if defined _STDINT_NEED_INT_LEAST_T +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +#ifdef _HAVE_UINT64_T +typedef int64_t int_least64_t; +#endif + +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +#ifdef _HAVE_UINT64_T +typedef uint64_t uint_least64_t; +#endif + /* least types */ +#endif + +#if defined _STDINT_NEED_INT_FAST_T +typedef int8_t int_fast8_t; +typedef int int_fast16_t; +typedef int32_t int_fast32_t; +#ifdef _HAVE_UINT64_T +typedef int64_t int_fast64_t; +#endif + +typedef uint8_t uint_fast8_t; +typedef unsigned uint_fast16_t; +typedef uint32_t uint_fast32_t; +#ifdef _HAVE_UINT64_T +typedef uint64_t uint_fast64_t; +#endif + /* fast types */ +#endif + +#ifdef _STDINT_NEED_INTMAX_T +#ifdef _HAVE_UINT64_T +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; +#else +typedef long intmax_t; +typedef unsigned long uintmax_t; +#endif +#endif + +#ifdef _STDINT_NEED_INTPTR_T +#ifndef __intptr_t_defined +#define __intptr_t_defined +/* we encourage using "long" to store pointer values, never use "int" ! */ +#if _STDINT_LONG_MODEL+0 == 242 || _STDINT_LONG_MODEL+0 == 484 +typedef unsigned int uintptr_t; +typedef int intptr_t; +#elif _STDINT_LONG_MODEL+0 == 244 || _STDINT_LONG_MODEL+0 == 444 +typedef unsigned long uintptr_t; +typedef long intptr_t; +#elif _STDINT_LONG_MODEL+0 == 448 && defined _HAVE_UINT64_T +typedef uint64_t uintptr_t; +typedef int64_t intptr_t; +#else /* matches typical system types ILP32 and LP64 - but not IP16 or LLP64 */ +typedef unsigned long uintptr_t; +typedef long intptr_t; +#endif +#endif +#endif + +/* The ISO C99 standard specifies that in C++ implementations these + should only be defined if explicitly requested. */ +#if !defined __cplusplus || defined __STDC_CONSTANT_MACROS +#ifndef UINT32_C + +/* Signed. */ +# define INT8_C(c) c +# define INT16_C(c) c +# define INT32_C(c) c +# ifdef _HAVE_LONGLONG_UINT64_T +# define INT64_C(c) c ## L +# else +# define INT64_C(c) c ## LL +# endif + +/* Unsigned. */ +# define UINT8_C(c) c ## U +# define UINT16_C(c) c ## U +# define UINT32_C(c) c ## U +# ifdef _HAVE_LONGLONG_UINT64_T +# define UINT64_C(c) c ## UL +# else +# define UINT64_C(c) c ## ULL +# endif + +/* Maximal type. */ +# ifdef _HAVE_LONGLONG_UINT64_T +# define INTMAX_C(c) c ## L +# define UINTMAX_C(c) c ## UL +# else +# define INTMAX_C(c) c ## LL +# define UINTMAX_C(c) c ## ULL +# endif + + /* literalnumbers */ +#endif +#endif + +/* These limits are merily those of a two complement byte-oriented system */ + +/* Minimum of signed integral types. */ +# define INT8_MIN (-128) +# define INT16_MIN (-32767-1) +# define INT32_MIN (-2147483647-1) +# define INT64_MIN (-__INT64_C(9223372036854775807)-1) +/* Maximum of signed integral types. */ +# define INT8_MAX (127) +# define INT16_MAX (32767) +# define INT32_MAX (2147483647) +# define INT64_MAX (__INT64_C(9223372036854775807)) + +/* Maximum of unsigned integral types. */ +# define UINT8_MAX (255) +# define UINT16_MAX (65535) +# define UINT32_MAX (4294967295U) +# define UINT64_MAX (__UINT64_C(18446744073709551615)) + +/* Minimum of signed integral types having a minimum size. */ +# define INT_LEAST8_MIN INT8_MIN +# define INT_LEAST16_MIN INT16_MIN +# define INT_LEAST32_MIN INT32_MIN +# define INT_LEAST64_MIN INT64_MIN +/* Maximum of signed integral types having a minimum size. */ +# define INT_LEAST8_MAX INT8_MAX +# define INT_LEAST16_MAX INT16_MAX +# define INT_LEAST32_MAX INT32_MAX +# define INT_LEAST64_MAX INT64_MAX + +/* Maximum of unsigned integral types having a minimum size. */ +# define UINT_LEAST8_MAX UINT8_MAX +# define UINT_LEAST16_MAX UINT16_MAX +# define UINT_LEAST32_MAX UINT32_MAX +# define UINT_LEAST64_MAX UINT64_MAX + + /* shortcircuit*/ +#endif + /* once */ +#endif +#endif +STDINT_EOF +fi + if cmp -s $ac_stdint_h $ac_stdint 2>/dev/null; then + AC_MSG_NOTICE([$ac_stdint_h is unchanged]) + else + ac_dir=`AS_DIRNAME(["$ac_stdint_h"])` + AS_MKDIR_P(["$ac_dir"]) + rm -f $ac_stdint_h + mv $ac_stdint $ac_stdint_h + fi +],[# variables for create stdint.h replacement +PACKAGE="$PACKAGE" +VERSION="$VERSION" +ac_stdint_h="$ac_stdint_h" +_ac_stdint_h=AS_TR_CPP(_$PACKAGE-$ac_stdint_h) +ac_cv_stdint_message="$ac_cv_stdint_message" +ac_cv_header_stdint_t="$ac_cv_header_stdint_t" +ac_cv_header_stdint_x="$ac_cv_header_stdint_x" +ac_cv_header_stdint_o="$ac_cv_header_stdint_o" +ac_cv_header_stdint_u="$ac_cv_header_stdint_u" +ac_cv_type_uint64_t="$ac_cv_type_uint64_t" +ac_cv_type_u_int64_t="$ac_cv_type_u_int64_t" +ac_cv_char_data_model="$ac_cv_char_data_model" +ac_cv_long_data_model="$ac_cv_long_data_model" +ac_cv_type_int_least32_t="$ac_cv_type_int_least32_t" +ac_cv_type_int_fast32_t="$ac_cv_type_int_fast32_t" +ac_cv_type_intmax_t="$ac_cv_type_intmax_t" +]) +]) diff --git a/common/m4/check.m4 b/common/m4/check.m4 new file mode 100755 index 0000000..19784ae --- /dev/null +++ b/common/m4/check.m4 @@ -0,0 +1,181 @@ +dnl _AM_TRY_CHECK(MINIMUM-VERSION, EXTRA-CFLAGS, EXTRA-LIBS, CHECK-LIB-NAME +dnl [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Test for check, and define CHECK_CFLAGS and CHECK_LIBS +dnl Done this way because of the brokenness that is +dnl https://launchpad.net/distros/ubuntu/+source/check/+bug/5840 +dnl + +AC_DEFUN([_AM_TRY_CHECK], +[ + min_check_version=$1 + extra_cflags=$2 + extra_libs=$3 + check_lib_name=$4 + + CHECK_CFLAGS="$extra_cflags" + CHECK_LIBS="$extra_libs -l$check_lib_name" + + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + + CFLAGS="$CFLAGS $CHECK_CFLAGS" + LIBS="$CHECK_LIBS $LIBS" + + AC_MSG_CHECKING(for check named $check_lib_name - version >= $min_check_version) + + rm -f conf.check-test + dnl unset no_check, since in our second run it would have been set to yes + dnl before + no_check= + AC_TRY_RUN([ +#include +#include + +#include + +int main () +{ + int major, minor, micro; + char *tmp_version; + + system ("touch conf.check-test"); + + /* HP/UX 9 (%@#!) writes to sscanf strings */ + tmp_version = strdup("$min_check_version"); + if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string\n", "$min_check_version"); + return 1; + } + + if ((CHECK_MAJOR_VERSION != check_major_version) || + (CHECK_MINOR_VERSION != check_minor_version) || + (CHECK_MICRO_VERSION != check_micro_version)) + { + printf("\n*** The check header file (version %d.%d.%d) does not match\n", + CHECK_MAJOR_VERSION, CHECK_MINOR_VERSION, CHECK_MICRO_VERSION); + printf("*** the check library (version %d.%d.%d).\n", + check_major_version, check_minor_version, check_micro_version); + return 1; + } + + if ((check_major_version > major) || + ((check_major_version == major) && (check_minor_version > minor)) || + ((check_major_version == major) && (check_minor_version == minor) && (check_micro_version >= micro))) + { + return 0; + } + else + { + printf("\n*** An old version of check (%d.%d.%d) was found.\n", + check_major_version, check_minor_version, check_micro_version); + printf("*** You need a version of check being at least %d.%d.%d.\n", major, minor, micro); + printf("***\n"); + printf("*** If you have already installed a sufficiently new version, this error\n"); + printf("*** probably means that the wrong copy of the check library and header\n"); + printf("*** file is being found. Rerun configure with the --with-check=PATH option\n"); + printf("*** to specify the prefix where the correct version was installed.\n"); + } + + return 1; +} +],, no_check=yes, [echo $ac_n "cross compiling; assumed OK... $ac_c"]) + + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + + if test "x$no_check" = x ; then + AC_MSG_RESULT(yes) + ifelse([$5], , :, [$5]) + else + AC_MSG_RESULT(no) + if test -f conf.check-test ; then + : + else + echo "*** Could not run check test program, checking why..." + CFLAGS="$CFLAGS $CHECK_CFLAGS" + LIBS="$CHECK_LIBS $LIBS" + AC_TRY_LINK([ +#include +#include + +#include +], , [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding check. 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" + echo "*** the exact error that occured." ]) + + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + + CHECK_CFLAGS="" + CHECK_LIBS="" + + rm -f conf.check-test + ifelse([$6], , AC_MSG_ERROR([check not found]), [$6]) + fi +]) + + +dnl AM_PATH_CHECK([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl Test for check, and define CHECK_CFLAGS and CHECK_LIBS +dnl + +AC_DEFUN([AM_PATH_CHECK], +[ + AC_ARG_WITH(check, + [ --with-check=PATH prefix where check is installed [default=auto]]) + + AC_ARG_WITH(checklibname, + AC_HELP_STRING([--with-check-lib-name=NAME], + [name of the PIC check library (default=check)])) + + min_check_version=ifelse([$1], ,0.8.2,$1) + + if test x$with_check = xno; then + AC_MSG_RESULT(disabled) + ifelse([$3], , AC_MSG_ERROR([disabling check is not supported]), [$3]) + else + if test "x$with_check" != x; then + CHECK_EXTRA_CFLAGS="-I$with_check/include" + CHECK_EXTRA_LIBS="-L$with_check/lib" + else + CHECK_EXTRA_CFLAGS="" + CHECK_EXTRA_LIBS="" + fi + + if test x$with_checklibname = x; then + _AM_TRY_CHECK($min_check_version, $CHECK_EXTRA_CFLAGS, $CHECK_EXTRA_LIBS, + check_pic, [have_check=true], [have_check=false]) + if test x$have_check = xtrue; then + ifelse([$2], , :, [$2]) + else + _AM_TRY_CHECK($min_check_version, $CHECK_EXTRA_CFLAGS, $CHECK_EXTRA_LIBS, + check, [have_check=true], [have_check=false]) + if test x$have_check = xtrue; then + ifelse([$2], , :, [$2]) + else + ifelse([$3], , AC_MSG_ERROR([check not found]), [$3]) + fi + fi + else + _AM_TRY_CHECK($min_check_version, $CHECK_EXTRA_CFLAGS, $CHECK_EXTRA_LIBS, + $with_checklibname, [have_check=true], [have_check=false]) + if test x$have_check = xtrue; then + ifelse([$2], , :, [$2]) + else + ifelse([$3], , AC_MSG_ERROR([check not found]), [$3]) + fi + fi + + AC_SUBST(CHECK_CFLAGS) + AC_SUBST(CHECK_LIBS) + rm -f conf.check-test + fi +]) diff --git a/common/m4/gettext.m4 b/common/m4/gettext.m4 new file mode 100755 index 0000000..45cad85 --- /dev/null +++ b/common/m4/gettext.m4 @@ -0,0 +1,587 @@ +# gettext.m4 serial 17 (gettext-0.11.5) +dnl Copyright (C) 1995-2002 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1995-2000. +dnl Bruno Haible , 2000-2002. + +dnl Macro to add for using GNU gettext. + +dnl Usage: AM_GNU_GETTEXT([INTLSYMBOL], [NEEDSYMBOL], [INTLDIR]). +dnl INTLSYMBOL can be one of 'external', 'no-libtool', 'use-libtool'. The +dnl default (if it is not specified or empty) is 'no-libtool'. +dnl INTLSYMBOL should be 'external' for packages with no intl directory, +dnl and 'no-libtool' or 'use-libtool' for packages with an intl directory. +dnl If INTLSYMBOL is 'use-libtool', then a libtool library +dnl $(top_builddir)/intl/libintl.la will be created (shared and/or static, +dnl depending on --{enable,disable}-{shared,static} and on the presence of +dnl AM-DISABLE-SHARED). If INTLSYMBOL is 'no-libtool', a static library +dnl $(top_builddir)/intl/libintl.a will be created. +dnl If NEEDSYMBOL is specified and is 'need-ngettext', then GNU gettext +dnl implementations (in libc or libintl) without the ngettext() function +dnl will be ignored. If NEEDSYMBOL is specified and is +dnl 'need-formatstring-macros', then GNU gettext implementations that don't +dnl support the ISO C 99 formatstring macros will be ignored. +dnl INTLDIR is used to find the intl libraries. If empty, +dnl the value `$(top_builddir)/intl/' is used. +dnl +dnl The result of the configuration is one of three cases: +dnl 1) GNU gettext, as included in the intl subdirectory, will be compiled +dnl and used. +dnl Catalog format: GNU --> install in $(datadir) +dnl Catalog extension: .mo after installation, .gmo in source tree +dnl 2) GNU gettext has been found in the system's C library. +dnl Catalog format: GNU --> install in $(datadir) +dnl Catalog extension: .mo after installation, .gmo in source tree +dnl 3) No internationalization, always use English msgid. +dnl Catalog format: none +dnl Catalog extension: none +dnl If INTLSYMBOL is 'external', only cases 2 and 3 can occur. +dnl The use of .gmo is historical (it was needed to avoid overwriting the +dnl GNU format catalogs when building on a platform with an X/Open gettext), +dnl but we keep it in order not to force irrelevant filename changes on the +dnl maintainers. +dnl +AC_DEFUN([AM_GNU_GETTEXT], +[ + dnl Argument checking. + ifelse([$1], [], , [ifelse([$1], [external], , [ifelse([$1], [no-libtool], , [ifelse([$1], [use-libtool], , + [errprint([ERROR: invalid first argument to AM_GNU_GETTEXT +])])])])]) + ifelse([$2], [], , [ifelse([$2], [need-ngettext], , [ifelse([$2], [need-formatstring-macros], , + [errprint([ERROR: invalid second argument to AM_GNU_GETTEXT +])])])]) + define(gt_included_intl, ifelse([$1], [external], [no], [yes])) + define(gt_libtool_suffix_prefix, ifelse([$1], [use-libtool], [l], [])) + + AC_REQUIRE([AM_PO_SUBDIRS])dnl + ifelse(gt_included_intl, yes, [ + AC_REQUIRE([AM_INTL_SUBDIR])dnl + ]) + + dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + + dnl Sometimes libintl requires libiconv, so first search for libiconv. + dnl Ideally we would do this search only after the + dnl if test "$USE_NLS" = "yes"; then + dnl if test "$gt_cv_func_gnugettext_libc" != "yes"; then + dnl tests. But if configure.in invokes AM_ICONV after AM_GNU_GETTEXT + dnl the configure script would need to contain the same shell code + dnl again, outside any 'if'. There are two solutions: + dnl - Invoke AM_ICONV_LINKFLAGS_BODY here, outside any 'if'. + dnl - Control the expansions in more detail using AC_PROVIDE_IFELSE. + dnl Since AC_PROVIDE_IFELSE is only in autoconf >= 2.52 and not + dnl documented, we avoid it. + ifelse(gt_included_intl, yes, , [ + AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) + ]) + + AC_MSG_CHECKING([whether NLS is requested]) + dnl Default is enabled NLS + AC_ARG_ENABLE(nls, + [ --disable-nls do not use Native Language Support], + USE_NLS=$enableval, USE_NLS=yes) + AC_MSG_RESULT($USE_NLS) + AC_SUBST(USE_NLS) + + ifelse(gt_included_intl, yes, [ + BUILD_INCLUDED_LIBINTL=no + USE_INCLUDED_LIBINTL=no + ]) + LIBINTL= + LTLIBINTL= + POSUB= + + dnl If we use NLS figure out what method + if test "$USE_NLS" = "yes"; then + gt_use_preinstalled_gnugettext=no + ifelse(gt_included_intl, yes, [ + AC_MSG_CHECKING([whether included gettext is requested]) + AC_ARG_WITH(included-gettext, + [ --with-included-gettext use the GNU gettext library included here], + nls_cv_force_use_gnu_gettext=$withval, + nls_cv_force_use_gnu_gettext=no) + AC_MSG_RESULT($nls_cv_force_use_gnu_gettext) + + nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" + if test "$nls_cv_force_use_gnu_gettext" != "yes"; then + ]) + dnl User does not insist on using GNU NLS library. Figure out what + dnl to use. If GNU gettext is available we use this. Else we have + dnl to fall back to GNU NLS library. + + dnl Add a version number to the cache macros. + define([gt_api_version], ifelse([$2], [need-formatstring-macros], 3, ifelse([$2], [need-ngettext], 2, 1))) + define([gt_cv_func_gnugettext_libc], [gt_cv_func_gnugettext]gt_api_version[_libc]) + define([gt_cv_func_gnugettext_libintl], [gt_cv_func_gnugettext]gt_api_version[_libintl]) + + AC_CACHE_CHECK([for GNU gettext in libc], gt_cv_func_gnugettext_libc, + [AC_TRY_LINK([#include +]ifelse([$2], [need-formatstring-macros], +[#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) +#endif +changequote(,)dnl +typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; +changequote([,])dnl +], [])[extern int _nl_msg_cat_cntr; +extern int *_nl_domain_bindings;], + [bindtextdomain ("", ""); +return (int) gettext ("")]ifelse([$2], [need-ngettext], [ + (int) ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_domain_bindings], + gt_cv_func_gnugettext_libc=yes, + gt_cv_func_gnugettext_libc=no)]) + + if test "$gt_cv_func_gnugettext_libc" != "yes"; then + dnl Sometimes libintl requires libiconv, so first search for libiconv. + ifelse(gt_included_intl, yes, , [ + AM_ICONV_LINK + ]) + dnl Search for libintl and define LIBINTL, LTLIBINTL and INCINTL + dnl accordingly. Don't use AC_LIB_LINKFLAGS_BODY([intl],[iconv]) + dnl because that would add "-liconv" to LIBINTL and LTLIBINTL + dnl even if libiconv doesn't exist. + AC_LIB_LINKFLAGS_BODY([intl]) + AC_CACHE_CHECK([for GNU gettext in libintl], + gt_cv_func_gnugettext_libintl, + [gt_save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $INCINTL" + gt_save_LIBS="$LIBS" + LIBS="$LIBS $LIBINTL" + dnl Now see whether libintl exists and does not depend on libiconv. + AC_TRY_LINK([#include +]ifelse([$2], [need-formatstring-macros], +[#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) +#endif +changequote(,)dnl +typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; +changequote([,])dnl +], [])[extern int _nl_msg_cat_cntr; +extern +#ifdef __cplusplus +"C" +#endif +const char *_nl_expand_alias ();], + [bindtextdomain ("", ""); +return (int) gettext ("")]ifelse([$2], [need-ngettext], [ + (int) ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_expand_alias (0)], + gt_cv_func_gnugettext_libintl=yes, + gt_cv_func_gnugettext_libintl=no) + dnl Now see whether libintl exists and depends on libiconv. + if test "$gt_cv_func_gnugettext_libintl" != yes && test -n "$LIBICONV"; then + LIBS="$LIBS $LIBICONV" + AC_TRY_LINK([#include +]ifelse([$2], [need-formatstring-macros], +[#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) +#endif +changequote(,)dnl +typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; +changequote([,])dnl +], [])[extern int _nl_msg_cat_cntr; +extern +#ifdef __cplusplus +"C" +#endif +const char *_nl_expand_alias ();], + [bindtextdomain ("", ""); +return (int) gettext ("")]ifelse([$2], [need-ngettext], [ + (int) ngettext ("", "", 0)], [])[ + _nl_msg_cat_cntr + *_nl_expand_alias (0)], + [LIBINTL="$LIBINTL $LIBICONV" + LTLIBINTL="$LTLIBINTL $LTLIBICONV" + gt_cv_func_gnugettext_libintl=yes + ]) + fi + CPPFLAGS="$gt_save_CPPFLAGS" + LIBS="$gt_save_LIBS"]) + fi + + dnl If an already present or preinstalled GNU gettext() is found, + dnl use it. But if this macro is used in GNU gettext, and GNU + dnl gettext is already preinstalled in libintl, we update this + dnl libintl. (Cf. the install rule in intl/Makefile.in.) + if test "$gt_cv_func_gnugettext_libc" = "yes" \ + || { test "$gt_cv_func_gnugettext_libintl" = "yes" \ + && test "$PACKAGE" != gettext; }; then + gt_use_preinstalled_gnugettext=yes + else + dnl Reset the values set by searching for libintl. + LIBINTL= + LTLIBINTL= + INCINTL= + fi + + ifelse(gt_included_intl, yes, [ + if test "$gt_use_preinstalled_gnugettext" != "yes"; then + dnl GNU gettext is not found in the C library. + dnl Fall back on included GNU gettext library. + nls_cv_use_gnu_gettext=yes + fi + fi + + if test "$nls_cv_use_gnu_gettext" = "yes"; then + dnl Mark actions used to generate GNU NLS library. + INTLOBJS="\$(GETTOBJS)" + BUILD_INCLUDED_LIBINTL=yes + USE_INCLUDED_LIBINTL=yes + LIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LIBICONV" + LTLIBINTL="ifelse([$3],[],\${top_builddir}/intl,[$3])/libintl.[]gt_libtool_suffix_prefix[]a $LTLIBICONV" + LIBS=`echo " $LIBS " | sed -e 's/ -lintl / /' -e 's/^ //' -e 's/ $//'` + fi + + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + dnl Mark actions to use GNU gettext tools. + CATOBJEXT=.gmo + fi + ]) + + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + AC_DEFINE(ENABLE_NLS, 1, + [Define to 1 if translation of program messages to the user's native language + is requested.]) + else + USE_NLS=no + fi + fi + + if test "$USE_NLS" = "yes"; then + + if test "$gt_use_preinstalled_gnugettext" = "yes"; then + if test "$gt_cv_func_gnugettext_libintl" = "yes"; then + AC_MSG_CHECKING([how to link with libintl]) + AC_MSG_RESULT([$LIBINTL]) + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCINTL]) + fi + + dnl For backward compatibility. Some packages may be using this. + AC_DEFINE(HAVE_GETTEXT, 1, + [Define if the GNU gettext() function is already present or preinstalled.]) + AC_DEFINE(HAVE_DCGETTEXT, 1, + [Define if the GNU dcgettext() function is already present or preinstalled.]) + fi + + dnl We need to process the po/ directory. + POSUB=po + fi + + ifelse(gt_included_intl, yes, [ + dnl If this is used in GNU gettext we have to set BUILD_INCLUDED_LIBINTL + dnl to 'yes' because some of the testsuite requires it. + if test "$PACKAGE" = gettext; then + BUILD_INCLUDED_LIBINTL=yes + fi + + dnl Make all variables we use known to autoconf. + AC_SUBST(BUILD_INCLUDED_LIBINTL) + AC_SUBST(USE_INCLUDED_LIBINTL) + AC_SUBST(CATOBJEXT) + AC_SUBST(INTLOBJS) + + dnl For backward compatibility. Some configure.ins may be using this. + nls_cv_header_intl= + nls_cv_header_libgt= + + dnl For backward compatibility. Some Makefiles may be using this. + DATADIRNAME=share + AC_SUBST(DATADIRNAME) + + dnl For backward compatibility. Some Makefiles may be using this. + INSTOBJEXT=.mo + AC_SUBST(INSTOBJEXT) + + dnl For backward compatibility. Some Makefiles may be using this. + GENCAT=gencat + AC_SUBST(GENCAT) + + dnl Enable libtool support if the surrounding package wishes it. + INTL_LIBTOOL_SUFFIX_PREFIX=gt_libtool_suffix_prefix + AC_SUBST(INTL_LIBTOOL_SUFFIX_PREFIX) + ]) + + dnl For backward compatibility. Some Makefiles may be using this. + INTLLIBS="$LIBINTL" + AC_SUBST(INTLLIBS) + + dnl Make all documented variables known to autoconf. + AC_SUBST(LIBINTL) + AC_SUBST(LTLIBINTL) + AC_SUBST(POSUB) +]) + + +dnl Checks for all prerequisites of the po subdirectory, +dnl except for USE_NLS. +AC_DEFUN([AM_PO_SUBDIRS], +[ + AC_REQUIRE([AC_PROG_MAKE_SET])dnl + AC_REQUIRE([AC_PROG_INSTALL])dnl + AC_REQUIRE([AM_MKINSTALLDIRS])dnl + + dnl Perform the following tests also if --disable-nls has been given, + dnl because they are needed for "make dist" to work. + + dnl Search for GNU msgfmt in the PATH. + dnl The first test excludes Solaris msgfmt and early GNU msgfmt versions. + dnl The second test excludes FreeBSD msgfmt. + AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, + [$ac_dir/$ac_word --statistics /dev/null >/dev/null 2>&1 && + (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], + :) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + + dnl Search for GNU xgettext 0.11 or newer in the PATH. + dnl The first test excludes Solaris xgettext and early GNU xgettext versions. + dnl The second test excludes FreeBSD xgettext. + AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, + [$ac_dir/$ac_word --omit-header --copyright-holder= /dev/null >/dev/null 2>&1 && + (if $ac_dir/$ac_word --omit-header --copyright-holder= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi)], + :) + dnl Remove leftover from FreeBSD xgettext call. + rm -f messages.po + + dnl Search for GNU msgmerge 0.11 or newer in the PATH. + AM_PATH_PROG_WITH_TEST(MSGMERGE, msgmerge, + [$ac_dir/$ac_word --update -q /dev/null /dev/null >/dev/null 2>&1], :) + + dnl This could go away some day; the PATH_PROG_WITH_TEST already does it. + dnl Test whether we really found GNU msgfmt. + if test "$GMSGFMT" != ":"; then + dnl If it is no GNU msgfmt we define it as : so that the + dnl Makefiles still can work. + if $GMSGFMT --statistics /dev/null >/dev/null 2>&1 && + (if $GMSGFMT --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then + : ; + else + GMSGFMT=`echo "$GMSGFMT" | sed -e 's,^.*/,,'` + AC_MSG_RESULT( + [found $GMSGFMT program is not GNU msgfmt; ignore it]) + GMSGFMT=":" + fi + fi + + dnl This could go away some day; the PATH_PROG_WITH_TEST already does it. + dnl Test whether we really found GNU xgettext. + if test "$XGETTEXT" != ":"; then + dnl If it is no GNU xgettext we define it as : so that the + dnl Makefiles still can work. + if $XGETTEXT --omit-header --copyright-holder= /dev/null >/dev/null 2>&1 && + (if $XGETTEXT --omit-header --copyright-holder= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then + : ; + else + AC_MSG_RESULT( + [found xgettext program is not GNU xgettext; ignore it]) + XGETTEXT=":" + fi + dnl Remove leftover from FreeBSD xgettext call. + rm -f messages.po + fi + + AC_OUTPUT_COMMANDS([ + for ac_file in $CONFIG_FILES; do + # Support "outfile[:infile[:infile...]]" + case "$ac_file" in + *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + esac + # PO directories have a Makefile.in generated from Makefile.in.in. + case "$ac_file" in */Makefile.in) + # Adjust a relative srcdir. + ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` + ac_dir_suffix="/`echo "$ac_dir"|sed 's%^\./%%'`" + ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` + # In autoconf-2.13 it is called $ac_given_srcdir. + # In autoconf-2.50 it is called $srcdir. + test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" + case "$ac_given_srcdir" in + .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; + /*) top_srcdir="$ac_given_srcdir" ;; + *) top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then + rm -f "$ac_dir/POTFILES" + test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" + cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" + # ALL_LINGUAS, POFILES, GMOFILES, UPDATEPOFILES, DUMMYPOFILES depend + # on $ac_dir but don't depend on user-specified configuration + # parameters. + if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then + # The LINGUAS file contains the set of available languages. + if test -n "$ALL_LINGUAS"; then + test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" + fi + ALL_LINGUAS_=`sed -e "/^#/d" "$ac_given_srcdir/$ac_dir/LINGUAS"` + # Hide the ALL_LINGUAS assigment from automake. + eval 'ALL_LINGUAS''=$ALL_LINGUAS_' + fi + case "$ac_given_srcdir" in + .) srcdirpre= ;; + *) srcdirpre='$(srcdir)/' ;; + esac + POFILES= + GMOFILES= + UPDATEPOFILES= + DUMMYPOFILES= + for lang in $ALL_LINGUAS; do + POFILES="$POFILES $srcdirpre$lang.po" + GMOFILES="$GMOFILES $srcdirpre$lang.gmo" + UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" + DUMMYPOFILES="$DUMMYPOFILES $lang.nop" + done + # CATALOGS depends on both $ac_dir and the user's LINGUAS + # environment variable. + INST_LINGUAS= + if test -n "$ALL_LINGUAS"; then + for presentlang in $ALL_LINGUAS; do + useit=no + if test "%UNSET%" != "$LINGUAS"; then + desiredlanguages="$LINGUAS" + else + desiredlanguages="$ALL_LINGUAS" + fi + for desiredlang in $desiredlanguages; do + # Use the presentlang catalog if desiredlang is + # a. equal to presentlang, or + # b. a variant of presentlang (because in this case, + # presentlang can be used as a fallback for messages + # which are not translated in the desiredlang catalog). + case "$desiredlang" in + "$presentlang"*) useit=yes;; + esac + done + if test $useit = yes; then + INST_LINGUAS="$INST_LINGUAS $presentlang" + fi + done + fi + CATALOGS= + if test -n "$INST_LINGUAS"; then + for lang in $INST_LINGUAS; do + CATALOGS="$CATALOGS $lang.gmo" + done + fi + test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" + sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" + for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do + if test -f "$f"; then + case "$f" in + *.orig | *.bak | *~) ;; + *) cat "$f" >> "$ac_dir/Makefile" ;; + esac + fi + done + fi + ;; + esac + done], + [# Capture the value of obsolete ALL_LINGUAS because we need it to compute + # POFILES, GMOFILES, UPDATEPOFILES, DUMMYPOFILES, CATALOGS. But hide it + # from automake. + eval 'ALL_LINGUAS''="$ALL_LINGUAS"' + # Capture the value of LINGUAS because we need it to compute CATALOGS. + LINGUAS="${LINGUAS-%UNSET%}" + ]) +]) + + +dnl Checks for all prerequisites of the intl subdirectory, +dnl except for INTL_LIBTOOL_SUFFIX_PREFIX (and possibly LIBTOOL), INTLOBJS, +dnl USE_INCLUDED_LIBINTL, BUILD_INCLUDED_LIBINTL. +AC_DEFUN([AM_INTL_SUBDIR], +[ + AC_REQUIRE([AC_PROG_INSTALL])dnl + AC_REQUIRE([AM_MKINSTALLDIRS])dnl + AC_REQUIRE([AC_PROG_CC])dnl + AC_REQUIRE([AC_CANONICAL_HOST])dnl + AC_REQUIRE([AC_PROG_RANLIB])dnl + AC_REQUIRE([AC_ISC_POSIX])dnl + AC_REQUIRE([AC_HEADER_STDC])dnl + AC_REQUIRE([AC_C_CONST])dnl + AC_REQUIRE([AC_C_INLINE])dnl + AC_REQUIRE([AC_TYPE_OFF_T])dnl + AC_REQUIRE([AC_TYPE_SIZE_T])dnl + AC_REQUIRE([AC_FUNC_ALLOCA])dnl + AC_REQUIRE([AC_FUNC_MMAP])dnl + AC_REQUIRE([jm_GLIBC21])dnl + AC_REQUIRE([gt_INTDIV0])dnl + AC_REQUIRE([jm_AC_TYPE_UINTMAX_T])dnl + AC_REQUIRE([gt_HEADER_INTTYPES_H])dnl + AC_REQUIRE([gt_INTTYPES_PRI])dnl + + AC_CHECK_HEADERS([argz.h limits.h locale.h nl_types.h malloc.h stddef.h \ +stdlib.h string.h unistd.h sys/param.h]) + AC_CHECK_FUNCS([feof_unlocked fgets_unlocked getc_unlocked getcwd getegid \ +geteuid getgid getuid mempcpy munmap putenv setenv setlocale stpcpy \ +strcasecmp strdup strtoul tsearch __argz_count __argz_stringify __argz_next]) + + AM_ICONV + AM_LANGINFO_CODESET + if test $ac_cv_header_locale_h = yes; then + AM_LC_MESSAGES + fi + + dnl intl/plural.c is generated from intl/plural.y. It requires bison, + dnl because plural.y uses bison specific features. It requires at least + dnl bison-1.26 because earlier versions generate a plural.c that doesn't + dnl compile. + dnl bison is only needed for the maintainer (who touches plural.y). But in + dnl order to avoid separate Makefiles or --enable-maintainer-mode, we put + dnl the rule in general Makefile. Now, some people carelessly touch the + dnl files or have a broken "make" program, hence the plural.c rule will + dnl sometimes fire. To avoid an error, defines BISON to ":" if it is not + dnl present or too old. + AC_CHECK_PROGS([INTLBISON], [bison]) + if test -z "$INTLBISON"; then + ac_verc_fail=yes + else + dnl Found it, now check the version. + AC_MSG_CHECKING([version of bison]) +changequote(<<,>>)dnl + ac_prog_version=`$INTLBISON --version 2>&1 | sed -n 's/^.*GNU Bison.* \([0-9]*\.[0-9.]*\).*$/\1/p'` + case $ac_prog_version in + '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;; + 1.2[6-9]* | 1.[3-9][0-9]* | [2-9].*) +changequote([,])dnl + ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;; + *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;; + esac + AC_MSG_RESULT([$ac_prog_version]) + fi + if test $ac_verc_fail = yes; then + INTLBISON=: + fi +]) + + +AC_DEFUN([AM_MKINSTALLDIRS], +[ + dnl If the AC_CONFIG_AUX_DIR macro for autoconf is used we possibly + dnl find the mkinstalldirs script in another subdir but $(top_srcdir). + dnl Try to locate is. + MKINSTALLDIRS= + if test -n "$ac_aux_dir"; then + MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs" + fi + if test -z "$MKINSTALLDIRS"; then + MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs" + fi + AC_SUBST(MKINSTALLDIRS) +]) + + +dnl Usage: AM_GNU_GETTEXT_VERSION([gettext-version]) +AC_DEFUN([AM_GNU_GETTEXT_VERSION], []) diff --git a/common/m4/glib-gettext.m4 b/common/m4/glib-gettext.m4 new file mode 100755 index 0000000..5a4ef28 --- /dev/null +++ b/common/m4/glib-gettext.m4 @@ -0,0 +1,380 @@ +# Copyright (C) 1995-2002 Free Software Foundation, Inc. +# Copyright (C) 2001-2003 Red Hat, Inc. +# +# This file is free software, distributed under the terms of the GNU +# General Public License. As a special exception to the GNU General +# Public License, this file may be distributed as part of a program +# that contains a configuration script generated by Autoconf, under +# the same distribution terms as the rest of that program. +# +# This file can be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# +# Macro to add for using GNU gettext. +# Ulrich Drepper , 1995, 1996 +# +# Modified to never use included libintl. +# Owen Taylor , 12/15/1998 +# +# Major rework to remove unused code +# Owen Taylor , 12/11/2002 +# +# Added better handling of ALL_LINGUAS from GNU gettext version +# written by Bruno Haible, Owen Taylor 5/30/3002 + +# +# We need this here as well, since someone might use autoconf-2.5x +# to configure GLib then an older version to configure a package +# using AM_GLIB_GNU_GETTEXT +AC_PREREQ(2.53) + +dnl +dnl We go to great lengths to make sure that aclocal won't +dnl try to pull in the installed version of these macros +dnl when running aclocal in the glib directory. +dnl +m4_copy([AC_DEFUN],[glib_DEFUN]) +m4_copy([AC_REQUIRE],[glib_REQUIRE]) +dnl +dnl At the end, if we're not within glib, we'll define the public +dnl definitions in terms of our private definitions. +dnl + +# GLIB_LC_MESSAGES +#-------------------- +glib_DEFUN([GLIB_LC_MESSAGES], + [AC_CHECK_HEADERS([locale.h]) + if test $ac_cv_header_locale_h = yes; then + AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES, + [AC_TRY_LINK([#include ], [return LC_MESSAGES], + am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)]) + if test $am_cv_val_LC_MESSAGES = yes; then + AC_DEFINE(HAVE_LC_MESSAGES, 1, + [Define if your file defines LC_MESSAGES.]) + fi + fi]) + +# GLIB_PATH_PROG_WITH_TEST +#---------------------------- +dnl GLIB_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, +dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) +glib_DEFUN([GLIB_PATH_PROG_WITH_TEST], +[# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_path_$1, +[case "[$]$1" in + /*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in ifelse([$5], , $PATH, [$5]); do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if [$3]; then + ac_cv_path_$1="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) + +# GLIB_WITH_NLS +#----------------- +glib_DEFUN([GLIB_WITH_NLS], + dnl NLS is obligatory + [USE_NLS=yes + AC_SUBST(USE_NLS) + + gt_cv_have_gettext=no + + CATOBJEXT=NONE + XGETTEXT=: + INTLLIBS= + + AC_CHECK_HEADER(libintl.h, + [gt_cv_func_dgettext_libintl="no" + libintl_extra_libs="" + + # + # First check in libc + # + AC_CACHE_CHECK([for dgettext in libc], gt_cv_func_dgettext_libc, + [AC_TRY_LINK([ +#include +], + [return (int) dgettext ("","")], + gt_cv_func_dgettext_libc=yes, + gt_cv_func_dgettext_libc=no) + ]) + + if test "$gt_cv_func_dgettext_libc" = "yes" ; then + AC_CHECK_FUNCS(bind_textdomain_codeset) + fi + + # + # If we don't have everything we want, check in libintl + # + if test "$gt_cv_func_dgettext_libc" != "yes" \ + || test "$ac_cv_func_bind_textdomain_codeset" != "yes" ; then + + AC_CHECK_LIB(intl, bindtextdomain, + [AC_CHECK_LIB(intl, dgettext, + gt_cv_func_dgettext_libintl=yes)]) + + if test "$gt_cv_func_dgettext_libintl" != "yes" ; then + AC_MSG_CHECKING([if -liconv is needed to use gettext]) + AC_MSG_RESULT([]) + AC_CHECK_LIB(intl, dcgettext, + [gt_cv_func_dgettext_libintl=yes + libintl_extra_libs=-liconv], + :,-liconv) + fi + + # + # If we found libintl, then check in it for bind_textdomain_codeset(); + # we'll prefer libc if neither have bind_textdomain_codeset(), + # and both have dgettext + # + if test "$gt_cv_func_dgettext_libintl" = "yes" ; then + glib_save_LIBS="$LIBS" + LIBS="$LIBS -lintl $libintl_extra_libs" + unset ac_cv_func_bind_textdomain_codeset + AC_CHECK_FUNCS(bind_textdomain_codeset) + LIBS="$glib_save_LIBS" + + if test "$ac_cv_func_bind_textdomain_codeset" = "yes" ; then + gt_cv_func_dgettext_libc=no + else + if test "$gt_cv_func_dgettext_libc" = "yes"; then + gt_cv_func_dgettext_libintl=no + fi + fi + fi + fi + + if test "$gt_cv_func_dgettext_libc" = "yes" \ + || test "$gt_cv_func_dgettext_libintl" = "yes"; then + gt_cv_have_gettext=yes + fi + + if test "$gt_cv_func_dgettext_libintl" = "yes"; then + INTLLIBS="-lintl $libintl_extra_libs" + fi + + if test "$gt_cv_have_gettext" = "yes"; then + AC_DEFINE(HAVE_GETTEXT,1, + [Define if the GNU gettext() function is already present or preinstalled.]) + GLIB_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], no)dnl + if test "$MSGFMT" != "no"; then + glib_save_LIBS="$LIBS" + LIBS="$LIBS $INTLLIBS" + AC_CHECK_FUNCS(dcgettext) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + GLIB_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) + AC_TRY_LINK(, [extern int _nl_msg_cat_cntr; + return _nl_msg_cat_cntr], + [CATOBJEXT=.gmo + DATADIRNAME=share], + [case $host in + *-*-solaris*) + dnl On Solaris, if bind_textdomain_codeset is in libc, + dnl GNU format message catalog is always supported, + dnl since both are added to the libc all together. + dnl Hence, we'd like to go with DATADIRNAME=share and + dnl and CATOBJEXT=.gmo in this case. + AC_CHECK_FUNC(bind_textdomain_codeset, + [CATOBJEXT=.gmo + DATADIRNAME=share], + [CATOBJEXT=.mo + DATADIRNAME=lib]) + ;; + *) + CATOBJEXT=.mo + DATADIRNAME=lib + ;; + esac]) + LIBS="$glib_save_LIBS" + INSTOBJEXT=.mo + else + gt_cv_have_gettext=no + fi + fi + ]) + + if test "$gt_cv_have_gettext" = "yes" ; then + AC_DEFINE(ENABLE_NLS, 1, + [always defined to indicate that i18n is enabled]) + fi + + dnl Test whether we really found GNU xgettext. + if test "$XGETTEXT" != ":"; then + dnl If it is not GNU xgettext we define it as : so that the + dnl Makefiles still can work. + if $XGETTEXT --omit-header /dev/null 2> /dev/null; then + : ; + else + AC_MSG_RESULT( + [found xgettext program is not GNU xgettext; ignore it]) + XGETTEXT=":" + fi + fi + + # We need to process the po/ directory. + POSUB=po + + AC_OUTPUT_COMMANDS( + [case "$CONFIG_FILES" in *po/Makefile.in*) + sed -e "/POTFILES =/r po/POTFILES" po/Makefile.in > po/Makefile + esac]) + + dnl These rules are solely for the distribution goal. While doing this + dnl we only have to keep exactly one list of the available catalogs + dnl in configure.in. + for lang in $ALL_LINGUAS; do + GMOFILES="$GMOFILES $lang.gmo" + POFILES="$POFILES $lang.po" + done + + dnl Make all variables we use known to autoconf. + AC_SUBST(CATALOGS) + AC_SUBST(CATOBJEXT) + AC_SUBST(DATADIRNAME) + AC_SUBST(GMOFILES) + AC_SUBST(INSTOBJEXT) + AC_SUBST(INTLLIBS) + AC_SUBST(PO_IN_DATADIR_TRUE) + AC_SUBST(PO_IN_DATADIR_FALSE) + AC_SUBST(POFILES) + AC_SUBST(POSUB) + ]) + +# AM_GLIB_GNU_GETTEXT +# ------------------- +# Do checks necessary for use of gettext. If a suitable implementation +# of gettext is found in either in libintl or in the C library, +# it will set INTLLIBS to the libraries needed for use of gettext +# and AC_DEFINE() HAVE_GETTEXT and ENABLE_NLS. (The shell variable +# gt_cv_have_gettext will be set to "yes".) It will also call AC_SUBST() +# on various variables needed by the Makefile.in.in installed by +# glib-gettextize. +dnl +glib_DEFUN([GLIB_GNU_GETTEXT], + [AC_REQUIRE([AC_PROG_CC])dnl + AC_REQUIRE([AC_HEADER_STDC])dnl + + GLIB_LC_MESSAGES + GLIB_WITH_NLS + + if test "$gt_cv_have_gettext" = "yes"; then + if test "x$ALL_LINGUAS" = "x"; then + LINGUAS= + else + AC_MSG_CHECKING(for catalogs to be installed) + NEW_LINGUAS= + for presentlang in $ALL_LINGUAS; do + useit=no + if test "%UNSET%" != "${LINGUAS-%UNSET%}"; then + desiredlanguages="$LINGUAS" + else + desiredlanguages="$ALL_LINGUAS" + fi + for desiredlang in $desiredlanguages; do + # Use the presentlang catalog if desiredlang is + # a. equal to presentlang, or + # b. a variant of presentlang (because in this case, + # presentlang can be used as a fallback for messages + # which are not translated in the desiredlang catalog). + case "$desiredlang" in + "$presentlang"*) useit=yes;; + esac + done + if test $useit = yes; then + NEW_LINGUAS="$NEW_LINGUAS $presentlang" + fi + done + LINGUAS=$NEW_LINGUAS + AC_MSG_RESULT($LINGUAS) + fi + + dnl Construct list of names of catalog files to be constructed. + if test -n "$LINGUAS"; then + for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done + fi + fi + + dnl If the AC_CONFIG_AUX_DIR macro for autoconf is used we possibly + dnl find the mkinstalldirs script in another subdir but ($top_srcdir). + dnl Try to locate is. + MKINSTALLDIRS= + if test -n "$ac_aux_dir"; then + MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs" + fi + if test -z "$MKINSTALLDIRS"; then + MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs" + fi + AC_SUBST(MKINSTALLDIRS) + + dnl Generate list of files to be processed by xgettext which will + dnl be included in po/Makefile. + test -d po || mkdir po + if test "x$srcdir" != "x."; then + if test "x`echo $srcdir | sed 's@/.*@@'`" = "x"; then + posrcprefix="$srcdir/" + else + posrcprefix="../$srcdir/" + fi + else + posrcprefix="../" + fi + rm -f po/POTFILES + sed -e "/^#/d" -e "/^\$/d" -e "s,.*, $posrcprefix& \\\\," -e "\$s/\(.*\) \\\\/\1/" \ + < $srcdir/po/POTFILES.in > po/POTFILES + ]) + +# AM_GLIB_DEFINE_LOCALEDIR(VARIABLE) +# ------------------------------- +# Define VARIABLE to the location where catalog files will +# be installed by po/Makefile. +glib_DEFUN([GLIB_DEFINE_LOCALEDIR], +[glib_REQUIRE([GLIB_GNU_GETTEXT])dnl +glib_save_prefix="$prefix" +glib_save_exec_prefix="$exec_prefix" +test "x$prefix" = xNONE && prefix=$ac_default_prefix +test "x$exec_prefix" = xNONE && exec_prefix=$prefix +if test "x$CATOBJEXT" = "x.mo" ; then + localedir=`eval echo "${libdir}/locale"` +else + localedir=`eval echo "${datadir}/locale"` +fi +prefix="$glib_save_prefix" +exec_prefix="$glib_save_exec_prefix" +AC_DEFINE_UNQUOTED($1, "$localedir", + [Define the location where the catalogs will be installed]) +]) + +dnl +dnl Now the definitions that aclocal will find +dnl +ifdef(glib_configure_in,[],[ +AC_DEFUN([AM_GLIB_GNU_GETTEXT],[GLIB_GNU_GETTEXT($@)]) +AC_DEFUN([AM_GLIB_DEFINE_LOCALEDIR],[GLIB_DEFINE_LOCALEDIR($@)]) +])dnl diff --git a/common/m4/gst-arch.m4 b/common/m4/gst-arch.m4 new file mode 100755 index 0000000..8a32bd2 --- /dev/null +++ b/common/m4/gst-arch.m4 @@ -0,0 +1,123 @@ +dnl AG_GST_ARCH +dnl sets up defines and automake conditionals for host architecture +dnl checks endianness +dnl defines HOST_CPU + +AC_DEFUN([AG_GST_ARCH], +[ + AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use host_ variables + + dnl Determine CPU + case "x${host_cpu}" in + xi?86 | xk? | xi?86_64) + HAVE_CPU_I386=yes + AC_DEFINE(HAVE_CPU_I386, 1, [Define if the host CPU is an x86]) + + dnl FIXME could use some better detection + dnl (ie CPUID) + case "x${host_cpu}" in + xi386 | xi486) ;; + *) + AC_DEFINE(HAVE_RDTSC, 1, [Define if RDTSC is available]) ;; + esac ;; + xpowerpc) + HAVE_CPU_PPC=yes + AC_DEFINE(HAVE_CPU_PPC, 1, [Define if the host CPU is a PowerPC]) ;; + xpowerpc64) + HAVE_CPU_PPC64=yes + AC_DEFINE(HAVE_CPU_PPC64, 1, [Define if the host CPU is a 64 bit PowerPC]) ;; + xalpha*) + HAVE_CPU_ALPHA=yes + AC_DEFINE(HAVE_CPU_ALPHA, 1, [Define if the host CPU is an Alpha]) ;; + xarm*) + HAVE_CPU_ARM=yes + AC_DEFINE(HAVE_CPU_ARM, 1, [Define if the host CPU is an ARM]) ;; + xsparc*) + HAVE_CPU_SPARC=yes + AC_DEFINE(HAVE_CPU_SPARC, 1, [Define if the host CPU is a SPARC]) ;; + xmips*) + HAVE_CPU_MIPS=yes + AC_DEFINE(HAVE_CPU_MIPS, 1, [Define if the host CPU is a MIPS]) ;; + xhppa*) + HAVE_CPU_HPPA=yes + AC_DEFINE(HAVE_CPU_HPPA, 1, [Define if the host CPU is a HPPA]) ;; + xs390*) + HAVE_CPU_S390=yes + AC_DEFINE(HAVE_CPU_S390, 1, [Define if the host CPU is a S390]) ;; + xia64*) + HAVE_CPU_IA64=yes + AC_DEFINE(HAVE_CPU_IA64, 1, [Define if the host CPU is a IA64]) ;; + xm68k*) + HAVE_CPU_M68K=yes + AC_DEFINE(HAVE_CPU_M68K, 1, [Define if the host CPU is a M68K]) ;; + xx86_64) + HAVE_CPU_X86_64=yes + AC_DEFINE(HAVE_CPU_X86_64, 1, [Define if the host CPU is a x86_64]) ;; + xcris) + HAVE_CPU_CRIS=yes + AC_DEFINE(HAVE_CPU_CRIS, 1, [Define if the host CPU is a CRIS]) ;; + xcrisv32) + HAVE_CPU_CRISV32=yes + AC_DEFINE(HAVE_CPU_CRISV32, 1, [Define if the host CPU is a CRISv32]) ;; + esac + + dnl Determine endianness + AC_C_BIGENDIAN + + AM_CONDITIONAL(HAVE_CPU_I386, test "x$HAVE_CPU_I386" = "xyes") + AM_CONDITIONAL(HAVE_CPU_PPC, test "x$HAVE_CPU_PPC" = "xyes") + AM_CONDITIONAL(HAVE_CPU_PPC64, test "x$HAVE_CPU_PPC64" = "xyes") + AM_CONDITIONAL(HAVE_CPU_ALPHA, test "x$HAVE_CPU_ALPHA" = "xyes") + AM_CONDITIONAL(HAVE_CPU_ARM, test "x$HAVE_CPU_ARM" = "xyes") + AM_CONDITIONAL(HAVE_CPU_SPARC, test "x$HAVE_CPU_SPARC" = "xyes") + AM_CONDITIONAL(HAVE_CPU_HPPA, test "x$HAVE_CPU_HPPA" = "xyes") + AM_CONDITIONAL(HAVE_CPU_MIPS, test "x$HAVE_CPU_MIPS" = "xyes") + AM_CONDITIONAL(HAVE_CPU_S390, test "x$HAVE_CPU_S390" = "xyes") + AM_CONDITIONAL(HAVE_CPU_IA64, test "x$HAVE_CPU_IA64" = "xyes") + AM_CONDITIONAL(HAVE_CPU_M68K, test "x$HAVE_CPU_M68K" = "xyes") + AM_CONDITIONAL(HAVE_CPU_X86_64, test "x$HAVE_CPU_X86_64" = "xyes") + AM_CONDITIONAL(HAVE_CPU_CRIS, test "x$HAVE_CPU_CRIS" = "xyes") + AM_CONDITIONAL(HAVE_CPU_CRISV32, test "x$HAVE_CPU_CRISV32" = "xyes") + + AC_DEFINE_UNQUOTED(HOST_CPU, "$host_cpu", [the host CPU]) +]) + +dnl check if unaligned memory access works correctly +AC_DEFUN([AG_GST_UNALIGNED_ACCESS], [ + AC_MSG_CHECKING([if unaligned memory access works correctly]) + if test x"$as_cv_unaligned_access" = x ; then + case $host in + alpha*|arm*|hp*|mips*|sh*|sparc*|ia64*) + _AS_ECHO_N([(blacklisted) ]) + as_cv_unaligned_access=no + ;; + i?86*|powerpc*|m68k*|cris*) + _AS_ECHO_N([(whitelisted) ]) + as_cv_unaligned_access=yes + ;; + esac + else + _AS_ECHO_N([(cached) ]) + fi + if test x"$as_cv_unaligned_access" = x ; then + AC_TRY_RUN([ +int main(int argc, char **argv) +{ + char array[] = "ABCDEFGH"; + unsigned int iarray[2]; + memcpy(iarray,array,8); +#define GET(x) (*(unsigned int *)((char *)iarray + (x))) + if(GET(0) != 0x41424344 && GET(0) != 0x44434241) return 1; + if(GET(1) != 0x42434445 && GET(1) != 0x45444342) return 1; + if(GET(2) != 0x43444546 && GET(2) != 0x46454443) return 1; + if(GET(3) != 0x44454647 && GET(3) != 0x47464544) return 1; + return 0; +} + ], as_cv_unaligned_access="yes", as_cv_unaligned_access="no") + fi + AC_MSG_RESULT($as_cv_unaligned_access) + if test "$as_cv_unaligned_access" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_UNALIGNED_ACCESS, 1, + [defined if unaligned memory access works correctly]) + fi +]) diff --git a/common/m4/gst-args.m4 b/common/m4/gst-args.m4 new file mode 100755 index 0000000..1781af4 --- /dev/null +++ b/common/m4/gst-args.m4 @@ -0,0 +1,302 @@ +dnl configure-time options shared among gstreamer modules + +dnl AG_GST_ARG_DEBUG +dnl AG_GST_ARG_PROFILING +dnl AG_GST_ARG_VALGRIND +dnl AG_GST_ARG_GCOV + +dnl AG_GST_ARG_EXAMPLES + +dnl AG_GST_ARG_WITH_PKG_CONFIG_PATH +dnl AG_GST_ARG_WITH_PACKAGE_NAME +dnl AG_GST_ARG_WITH_PACKAGE_ORIGIN + +dnl AG_GST_ARG_WITH_PLUGINS +dnl AG_GST_CHECK_PLUGIN +dnl AG_GST_DISABLE_PLUGIN + +dnl AG_GST_ARG_ENABLE_EXTERNAL +dnl AG_GST_ARG_ENABLE_EXPERIMENTAL +dnl AG_GST_ARG_ENABLE_BROKEN + +AC_DEFUN([AG_GST_ARG_DEBUG], +[ + dnl debugging stuff + AC_ARG_ENABLE(debug, + AC_HELP_STRING([--disable-debug],[disable addition of -g debugging info]), + [ + case "${enableval}" in + yes) USE_DEBUG=yes ;; + no) USE_DEBUG=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-debug) ;; + esac + ], + [USE_DEBUG=yes]) dnl Default value +]) + +AC_DEFUN([AG_GST_ARG_PROFILING], +[ + AC_ARG_ENABLE(profiling, + AC_HELP_STRING([--enable-profiling], + [adds -pg to compiler commandline, for profiling]), + [ + case "${enableval}" in + yes) USE_PROFILING=yes ;; + no) USE_PROFILING=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-profiling) ;; + esac + ], + [USE_PROFILING=no]) dnl Default value +]) + +AC_DEFUN([AG_GST_ARG_VALGRIND], +[ + dnl valgrind inclusion + AC_ARG_ENABLE(valgrind, + AC_HELP_STRING([--disable-valgrind],[disable run-time valgrind detection]), + [ + case "${enableval}" in + yes) USE_VALGRIND="$USE_DEBUG" ;; + no) USE_VALGRIND=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-valgrind) ;; + esac + ], + [USE_VALGRIND="$USE_DEBUG"]) dnl Default value + VALGRIND_REQ="2.1" + if test "x$USE_VALGRIND" = xyes; then + PKG_CHECK_MODULES(VALGRIND, valgrind > $VALGRIND_REQ, + USE_VALGRIND="yes", + [ + USE_VALGRIND="no" + AC_MSG_RESULT([no]) + ]) + fi + if test "x$USE_VALGRIND" = xyes; then + AC_DEFINE(HAVE_VALGRIND, 1, [Define if valgrind should be used]) + AC_MSG_NOTICE(Using extra code paths for valgrind) + fi +]) + +AC_DEFUN([AG_GST_ARG_GCOV], +[ + AC_ARG_ENABLE(gcov, + AC_HELP_STRING([--enable-gcov], + [compile with coverage profiling instrumentation (gcc only)]), + enable_gcov=$enableval, + enable_gcov=no) + if test x$enable_gcov = xyes ; then + if test "x$GCC" != "xyes" + then + AC_MSG_ERROR([gcov only works if gcc is used]) + fi + + AS_COMPILER_FLAG(["-fprofile-arcs"], + [GCOV_CFLAGS="$GCOV_CFLAGS -fprofile-arcs"], + true) + AS_COMPILER_FLAG(["-ftest-coverage"], + [GCOV_CFLAGS="$GCOV_CFLAGS -ftest-coverage"], + true) + dnl remove any -O flags - FIXME: is this needed ? + GCOV_CFLAGS=`echo "$GCOV_CFLAGS" | sed -e 's/-O[[0-9]]*//g'` + dnl libtool 1.5.22 and lower strip -fprofile-arcs from the flags + dnl passed to the linker, which is a bug; -fprofile-arcs implicitly + dnl links in -lgcov, so we do it explicitly here for the same effect + GCOV_LIBS=-lgcov + AC_SUBST(GCOV_CFLAGS) + AC_SUBST(GCOV_LIBS) + GCOV=`echo $CC | sed s/gcc/gcov/g` + AC_SUBST(GCOV) + + GST_GCOV_ENABLED=yes + AC_DEFINE_UNQUOTED(GST_GCOV_ENABLED, 1, + [Defined if gcov is enabled to force a rebuild due to config.h changing]) + dnl if gcov is used, we do not want default -O2 CFLAGS + if test "x$GST_GCOV_ENABLED" = "xyes" + then + CFLAGS="-O0" + AC_SUBST(CFLAGS) + CXXFLAGS="-O0" + AC_SUBST(CXXFLAGS) + FFLAGS="-O0" + AC_SUBST(FFLAGS) + CCASFLAGS="-O0" + AC_SUBST(CCASFLAGS) + AC_MSG_NOTICE([gcov enabled, setting CFLAGS and friends to $CFLAGS]) + fi + fi + AM_CONDITIONAL(GST_GCOV_ENABLED, test x$enable_gcov = xyes) +]) + +AC_DEFUN([AG_GST_ARG_EXAMPLES], +[ + AC_ARG_ENABLE(examples, + AC_HELP_STRING([--disable-examples], [disable building examples]), + [ + case "${enableval}" in + yes) BUILD_EXAMPLES=yes ;; + no) BUILD_EXAMPLES=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-examples) ;; + esac + ], + [BUILD_EXAMPLES=yes]) dnl Default value + AM_CONDITIONAL(BUILD_EXAMPLES, test "x$BUILD_EXAMPLES" = "xyes") +]) + +AC_DEFUN([AG_GST_ARG_WITH_PKG_CONFIG_PATH], +[ + dnl possibly modify pkg-config path + AC_ARG_WITH(pkg-config-path, + AC_HELP_STRING([--with-pkg-config-path], + [colon-separated list of pkg-config(1) dirs]), + [ + export PKG_CONFIG_PATH=${withval} + AC_MSG_NOTICE(Set PKG_CONFIG_PATH to $PKG_CONFIG_PATH) + ]) +]) + + +dnl This macro requires that GST_CVS is set to yes or no (release) +AC_DEFUN([AG_GST_ARG_WITH_PACKAGE_NAME], +[ + dnl package name in plugins + AC_ARG_WITH(package-name, + AC_HELP_STRING([--with-package-name], + [specify package name to use in plugins]), + [ + case "${withval}" in + yes) AC_MSG_ERROR(bad value ${withval} for --with-package-name) ;; + no) AC_MSG_ERROR(bad value ${withval} for --with-package-name) ;; + *) GST_PACKAGE_NAME="${withval}" ;; + esac + ], + [ + P=$1 + if test "x$P" = "x" + then + P=$PACKAGE_NAME + fi + + dnl default value + if test "x$GST_CVS" = "xyes" + then + dnl nano >= 1 + GST_PACKAGE_NAME="$P CVS/prerelease" + else + GST_PACKAGE_NAME="$P source release" + fi + ] + ) + AC_MSG_NOTICE(Using $GST_PACKAGE_NAME as package name) + AC_DEFINE_UNQUOTED(GST_PACKAGE_NAME, "$GST_PACKAGE_NAME", + [package name in plugins]) + AC_SUBST(GST_PACKAGE_NAME) +]) + +AC_DEFUN([AG_GST_ARG_WITH_PACKAGE_ORIGIN], +[ + dnl package origin URL + AC_ARG_WITH(package-origin, + AC_HELP_STRING([--with-package-origin], + [specify package origin URL to use in plugins]), + [ + case "${withval}" in + yes) AC_MSG_ERROR(bad value ${withval} for --with-package-origin) ;; + no) AC_MSG_ERROR(bad value ${withval} for --with-package-origin) ;; + *) GST_PACKAGE_ORIGIN="${withval}" ;; + esac + ], + [GST_PACKAGE_ORIGIN="[Unknown package origin]"] dnl Default value + ) + AC_MSG_NOTICE(Using $GST_PACKAGE_ORIGIN as package origin) + AC_DEFINE_UNQUOTED(GST_PACKAGE_ORIGIN, "$GST_PACKAGE_ORIGIN", + [package origin]) + AC_SUBST(GST_PACKAGE_ORIGIN) +]) + +dnl sets WITH_PLUGINS to the list of plug-ins given as an argument +dnl also clears GST_PLUGINS_ALL and GST_PLUGINS_SELECTED +AC_DEFUN([AG_GST_ARG_WITH_PLUGINS], +[ + AC_ARG_WITH(plugins, + AC_HELP_STRING([--with-plugins], + [comma-separated list of dependencyless plug-ins to compile]), + [WITH_PLUGINS=$withval], + [WITH_PLUGINS=]) + + GST_PLUGINS_ALL="" + GST_PLUGINS_SELECTED="" + + AC_SUBST(GST_PLUGINS_ALL) + AC_SUBST(GST_PLUGINS_SELECTED) +]) + +dnl AG_GST_CHECK_PLUGIN(PLUGIN-NAME) +dnl +dnl This macro adds the plug-in to GST_PLUGINS_ALL. Then it +dnl checks if the plug-in is present in WITH_PLUGINS, and if so adds it to +dnl GST_PLUGINS_SELECTED. +dnl +dnl The macro will call AM_CONDITIONAL(USE_PLUGIN_, ...) to allow +dnl control of what is built in Makefile.ams. +AC_DEFUN([AG_GST_CHECK_PLUGIN], +[ + GST_PLUGINS_ALL="$GST_PLUGINS_ALL [$1]" + if [[ -z "$WITH_PLUGINS" ]] || echo " [$WITH_PLUGINS] " | tr , ' ' | grep -i " [$1] " > /dev/null; then + GST_PLUGINS_SELECTED="$GST_PLUGINS_SELECTED [$1]" + fi + AM_CONDITIONAL([USE_PLUGIN_]translit([$1], a-z, A-Z), echo " $GST_PLUGINS_SELECTED " | grep -i " [$1] " > /dev/null) +]) + +dnl AG_GST_DISABLE_PLUGIN(PLUGIN-NAME) +dnl +dnl This macro disables the plug-in by removing it from +dnl GST_PLUGINS_SELECTED. +AC_DEFUN([AG_GST_DISABLE_PLUGIN], +[ + GST_PLUGINS_SELECTED=`echo " $GST_PLUGINS_SELECTED " | $SED -e 's/ [$1] / /'` + AM_CONDITIONAL([USE_PLUGIN_]translit([$1], a-z, A-Z), false) +]) + +AC_DEFUN([AG_GST_ARG_ENABLE_EXTERNAL], +[ + AG_GST_CHECK_FEATURE(EXTERNAL, [building of plug-ins with external deps],, + HAVE_EXTERNAL=yes, enabled, + [ + AC_MSG_NOTICE(building external plug-ins) + BUILD_EXTERNAL="yes" + ],[ + AC_MSG_WARN(all plug-ins with external dependencies will not be built) + BUILD_EXTERNAL="no" + ]) + # make BUILD_EXTERNAL available to Makefile.am + AM_CONDITIONAL(BUILD_EXTERNAL, test "x$BUILD_EXTERNAL" = "xyes") +]) + +dnl experimental plug-ins; stuff that hasn't had the dust settle yet +dnl read 'builds, but might not work' +AC_DEFUN([AG_GST_ARG_ENABLE_EXPERIMENTAL], +[ + AG_GST_CHECK_FEATURE(EXPERIMENTAL, [building of experimental plug-ins],, + HAVE_EXPERIMENTAL=yes, disabled, + [ + AC_MSG_WARN(building experimental plug-ins) + BUILD_EXPERIMENTAL="yes" + ],[ + AC_MSG_NOTICE(not building experimental plug-ins) + BUILD_EXPERIMENTAL="no" + ]) + # make BUILD_EXPERIMENTAL available to Makefile.am + AM_CONDITIONAL(BUILD_EXPERIMENTAL, test "x$BUILD_EXPERIMENTAL" = "xyes") +]) + +dnl broken plug-ins; stuff that doesn't seem to build at the moment +AC_DEFUN([AG_GST_ARG_ENABLE_BROKEN], +[ + AG_GST_CHECK_FEATURE(BROKEN, [building of broken plug-ins],, + HAVE_BROKEN=yes, disabled, + [ + AC_MSG_WARN([building broken plug-ins -- no bug reports on these, only patches ...]) + ],[ + AC_MSG_NOTICE([not building broken plug-ins]) + ]) +]) diff --git a/common/m4/gst-check.m4 b/common/m4/gst-check.m4 new file mode 100755 index 0000000..3f6b8ff --- /dev/null +++ b/common/m4/gst-check.m4 @@ -0,0 +1,138 @@ +dnl pkg-config-based checks for GStreamer modules and dependency modules + +dnl generic: +dnl AG_GST_PKG_CHECK_MODULES([PREFIX], [WHICH], [REQUIRED]) +dnl sets HAVE_[$PREFIX], [$PREFIX]_* +dnl AG_GST_CHECK_MODULES([PREFIX], [MODULE], [MINVER], [NAME], [REQUIRED]) +dnl sets HAVE_[$PREFIX], [$PREFIX]_* + +dnl specific: +dnl AG_GST_CHECK_GST([MAJMIN], [MINVER], [REQUIRED]) +dnl also sets/ACSUBSTs GST_TOOLS_DIR and GST_PLUGINS_DIR +dnl AG_GST_CHECK_GST_BASE([MAJMIN], [MINVER], [REQUIRED]) +dnl AG_GST_CHECK_GST_GDP([MAJMIN], [MINVER], [REQUIRED]) +dnl AG_GST_CHECK_GST_CONTROLLER([MAJMIN], [MINVER], [REQUIRED]) +dnl AG_GST_CHECK_GST_CHECK([MAJMIN], [MINVER], [REQUIRED]) +dnl AG_GST_CHECK_GST_PLUGINS_BASE([MAJMIN], [MINVER], [REQUIRED]) +dnl also sets/ACSUBSTs GSTPB_PLUGINS_DIR + +AC_DEFUN([AG_GST_PKG_CHECK_MODULES], +[ + which="[$2]" + dnl not required by default, since we use this mostly for plugin deps + required=ifelse([$3], , "no", [$3]) + + PKG_CHECK_MODULES([$1], $which, + [ + HAVE_[$1]="yes" + ], + [ + HAVE_[$1]="no" + AC_MSG_RESULT(no) + if test "x$required" = "xyes"; then + AC_MSG_ERROR($[$1]_PKG_ERRORS) + else + AC_MSG_NOTICE($[$1]_PKG_ERRORS) + fi + ]) + + dnl AC_SUBST of CFLAGS and LIBS was not done before automake 1.7 + dnl It gets done automatically in automake >= 1.7, which we now require +])) + +AC_DEFUN([AG_GST_CHECK_MODULES], +[ + module=[$2] + minver=[$3] + name="[$4]" + required=ifelse([$5], , "yes", [$5]) dnl required by default + + PKG_CHECK_MODULES([$1], $module >= $minver, + [ + HAVE_[$1]="yes" + ], + [ + HAVE_[$1]="no" + AC_MSG_RESULT(no) + AC_MSG_NOTICE($[$1]_PKG_ERRORS) + if test "x$required" = "xyes"; then + AC_MSG_ERROR([no $module >= $minver ($name) found]) + else + AC_MSG_NOTICE([no $module >= $minver ($name) found]) + fi + ]) + + dnl AC_SUBST of CFLAGS and LIBS was not done before automake 1.7 + dnl It gets done automatically in automake >= 1.7, which we now require +])) + +AC_DEFUN([AG_GST_CHECK_GST], +[ + AG_GST_CHECK_MODULES(GST, gstreamer-[$1], [$2], [GStreamer], [$3]) + dnl allow setting before calling this macro to override + if test -z $GST_TOOLS_DIR; then + GST_TOOLS_DIR=`$PKG_CONFIG --variable=toolsdir gstreamer-[$1]` + if test -z $GST_TOOLS_DIR; then + AC_MSG_ERROR( + [no tools dir set in GStreamer pkg-config file, core upgrade needed.]) + fi + fi + AC_MSG_NOTICE([using GStreamer tools in $GST_TOOLS_DIR]) + AC_SUBST(GST_TOOLS_DIR) + + dnl check for where core plug-ins got installed + dnl this is used for unit tests + dnl allow setting before calling this macro to override + if test -z $GST_PLUGINS_DIR; then + GST_PLUGINS_DIR=`$PKG_CONFIG --variable=pluginsdir gstreamer-[$1]` + if test -z $GST_PLUGINS_DIR; then + AC_MSG_ERROR( + [no pluginsdir set in GStreamer pkg-config file, core upgrade needed.]) + fi + fi + AC_MSG_NOTICE([using GStreamer plug-ins in $GST_PLUGINS_DIR]) + AC_SUBST(GST_PLUGINS_DIR) +]) + +AC_DEFUN([AG_GST_CHECK_GST_BASE], +[ + AG_GST_CHECK_MODULES(GST_BASE, gstreamer-base-[$1], [$2], + [GStreamer Base Libraries], [$3]) +]) + +AC_DEFUN([AG_GST_CHECK_GST_GDP], +[ + AG_GST_CHECK_MODULES(GST_GDP, gstreamer-dataprotocol-[$1], [$2], + [GStreamer Data Protocol Library], [$3]) +]) + +AC_DEFUN([AG_GST_CHECK_GST_CONTROLLER], +[ + AG_GST_CHECK_MODULES(GST_CONTROLLER, gstreamer-controller-[$1], [$2], + [GStreamer Controller Library], [$3]) +]) + +AC_DEFUN([AG_GST_CHECK_GST_CHECK], +[ + AG_GST_CHECK_MODULES(GST_CHECK, gstreamer-check-[$1], [$2], + [GStreamer Check unittest Library], [$3]) +]) + +AC_DEFUN([AG_GST_CHECK_GST_PLUGINS_BASE], +[ + AG_GST_CHECK_MODULES(GST_PLUGINS_BASE, gstreamer-plugins-base-[$1], [$2], + [GStreamer Base Plug-ins Library], [$3]) + + dnl check for where base plug-ins got installed + dnl this is used for unit tests + dnl allow setting before calling this macro to override + if test -z $GSTPB_PLUGINS_DIR; then + GSTPB_PLUGINS_DIR=`$PKG_CONFIG --variable=pluginsdir gstreamer-plugins-base-[$1]` + if test -z $GSTPB_PLUGINS_DIR; then + AC_MSG_ERROR( + [no pluginsdir set in GStreamer Base Plug-ins pkg-config file]) + fi + fi + AC_MSG_NOTICE([using GStreamer Base Plug-ins in $GSTPB_PLUGINS_DIR]) + AC_SUBST(GSTPB_PLUGINS_DIR) +]) diff --git a/common/m4/gst-debuginfo.m4 b/common/m4/gst-debuginfo.m4 new file mode 100755 index 0000000..b48854d --- /dev/null +++ b/common/m4/gst-debuginfo.m4 @@ -0,0 +1,46 @@ +AC_DEFUN([AG_GST_DEBUGINFO], [ +AC_ARG_ENABLE(debug, +AC_HELP_STRING([--disable-debug],[disable addition of -g debugging info]), +[case "${enableval}" in + yes) USE_DEBUG=yes ;; + no) USE_DEBUG=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-debug) ;; +esac], +[USE_DEBUG=yes]) dnl Default value + +AC_ARG_ENABLE(DEBUG, +AC_HELP_STRING([--disable-DEBUG],[disables compilation of debugging messages]), +[case "${enableval}" in + yes) ENABLE_DEBUG=yes ;; + no) ENABLE_DEBUG=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-DEBUG) ;; +esac], +[ENABLE_DEBUG=yes]) dnl Default value +if test x$ENABLE_DEBUG = xyes; then + AC_DEFINE(GST_DEBUG_ENABLED, 1, [Define if DEBUG statements should be compiled in]) +fi + +AC_ARG_ENABLE(INFO, +AC_HELP_STRING([--disable-INFO],[disables compilation of informational messages]), +[case "${enableval}" in + yes) ENABLE_INFO=yes ;; + no) ENABLE_INFO=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-INFO) ;; +esac], +[ENABLE_INFO=yes]) dnl Default value +if test x$ENABLE_INFO = xyes; then + AC_DEFINE(GST_INFO_ENABLED, 1, [Define if INFO statements should be compiled in]) +fi + +AC_ARG_ENABLE(debug-color, +AC_HELP_STRING([--disable-debug-color],[disables color output of DEBUG and INFO output]), +[case "${enableval}" in + yes) ENABLE_DEBUG_COLOR=yes ;; + no) ENABLE_DEBUG_COLOR=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-debug-color) ;; +esac], +[ENABLE_DEBUG_COLOR=yes]) dnl Default value +if test "x$ENABLE_DEBUG_COLOR" = xyes; then + AC_DEFINE(GST_DEBUG_COLOR, 1, [Define if debugging messages should be colorized]) +fi +]) diff --git a/common/m4/gst-default.m4 b/common/m4/gst-default.m4 new file mode 100755 index 0000000..da1a81c --- /dev/null +++ b/common/m4/gst-default.m4 @@ -0,0 +1,45 @@ +dnl default elements used for tests and such + +dnl AG_GST_DEFAULT_ELEMENTS + +AC_DEFUN([AG_GST_DEFAULT_ELEMENTS], +[ + dnl decide on default elements + dnl FIXME: provide configure-time options for this + dnl FIXME: describe where exactly this gets used + dnl FIXME: decide if it's a problem that this could point to sinks from + dnl depending plugin modules + DEFAULT_AUDIOSINK="autoaudiosink" + DEFAULT_VIDEOSINK="autovideosink" + DEFAULT_AUDIOSRC="alsasrc" + DEFAULT_VIDEOSRC="v4lsrc" + DEFAULT_VISUALIZER="goom" + case "$host" in + *-sun-* | *pc-solaris* ) + DEFAULT_AUDIOSINK="sunaudiosink" + DEFAULT_VIDEOSINK="ximagesink" + DEFAULT_AUDIOSRC="sunaudiosrc" + ;; + *-darwin* ) + DEFAULT_AUDIOSINK="osxaudiosink" + DEFAULT_AUDIOSRC="osxaudiosrc" + DEFAULT_VIDEOSINK="osxvideosink" + ;; + esac + + AC_SUBST(DEFAULT_AUDIOSINK) + AC_DEFINE_UNQUOTED(DEFAULT_AUDIOSINK, "$DEFAULT_AUDIOSINK", + [Default audio sink]) + AC_SUBST(DEFAULT_AUDIOSRC) + AC_DEFINE_UNQUOTED(DEFAULT_AUDIOSRC, "$DEFAULT_AUDIOSRC", + [Default audio source]) + AC_SUBST(DEFAULT_VIDEOSINK) + AC_DEFINE_UNQUOTED(DEFAULT_VIDEOSINK, "$DEFAULT_VIDEOSINK", + [Default video sink]) + AC_SUBST(DEFAULT_VIDEOSRC) + AC_DEFINE_UNQUOTED(DEFAULT_VIDEOSRC, "$DEFAULT_VIDEOSRC", + [Default video source]) + AC_SUBST(DEFAULT_VISUALIZER) + AC_DEFINE_UNQUOTED(DEFAULT_VISUALIZER, "$DEFAULT_VISUALIZER", + [Default visualizer]) +]) diff --git a/common/m4/gst-doc.m4 b/common/m4/gst-doc.m4 new file mode 100755 index 0000000..7000c17 --- /dev/null +++ b/common/m4/gst-doc.m4 @@ -0,0 +1,148 @@ +AC_DEFUN([AG_GST_DOCBOOK_CHECK], +[ + dnl choose a location to install docbook docs in + if test "x$PACKAGE_TARNAME" = "x" + then + AC_MSG_ERROR([Internal error - PACKAGE_TARNAME not set]) + fi + docdir="\$(datadir)/doc/$PACKAGE_TARNAME-$GST_MAJORMINOR" + + dnl enable/disable docbook documentation building + AC_ARG_ENABLE(docbook, + AC_HELP_STRING([--enable-docbook], + [use docbook to build documentation [default=no]]),, + enable_docbook=no) + + have_docbook=no + + if test x$enable_docbook = xyes; then + dnl check if we actually have everything we need + + dnl check for docbook tools + AC_CHECK_PROG(HAVE_DOCBOOK2PS, docbook2ps, yes, no) + AC_CHECK_PROG(HAVE_DOCBOOK2HTML, docbook2html, yes, no) + AC_CHECK_PROG(HAVE_JADETEX, jadetex, yes, no) + AC_CHECK_PROG(HAVE_PS2PDF, ps2pdf, yes, no) + + # -V option appeared in 0.6.10 + docbook2html_min_version=0.6.10 + if test "x$HAVE_DOCBOOK2HTML" != "xno"; then + docbook2html_version=`docbook2html --version` + AC_MSG_CHECKING([docbook2html version ($docbook2html_version) >= $docbook2html_min_version]) + if perl -w < \$min_version_major) || + ((\$docbook2html_version_major == \$min_version_major) && + (\$docbook2html_version_minor >= \$min_version_minor)) || + ((\$docbook2html_version_major == \$min_version_major) && + (\$docbook2html_version_minor >= \$min_version_minor) && + (\$docbook2html_version_micro >= \$min_version_micro))) + ? 0 : 1); +EOF + then + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + HAVE_DOCBOOK2HTML=no + fi + fi + + dnl check if we can process docbook stuff + AS_DOCBOOK(have_docbook=yes, have_docbook=no) + + dnl check for extra tools + AC_CHECK_PROG(HAVE_DVIPS, dvips, yes, no) + AC_CHECK_PROG(HAVE_XMLLINT, xmllint, yes, no) + + dnl check for image conversion tools + AC_CHECK_PROG(HAVE_FIG2DEV, fig2dev, yes, no) + if test "x$HAVE_FIG2DEV" = "xno" ; then + AC_MSG_WARN([Did not find fig2dev (from xfig), images will not be generated.]) + fi + + dnl The following is a hack: if fig2dev doesn't display an error message + dnl for the desired type, we assume it supports it. + HAVE_FIG2DEV_EPS=no + if test "x$HAVE_FIG2DEV" = "xyes" ; then + fig2dev_quiet=`fig2dev -L eps &1 >/dev/null` + if test "x$fig2dev_quiet" = "x" ; then + HAVE_FIG2DEV_EPS=yes + fi + fi + HAVE_FIG2DEV_PNG=no + if test "x$HAVE_FIG2DEV" = "xyes" ; then + fig2dev_quiet=`fig2dev -L png &1 >/dev/null` + if test "x$fig2dev_quiet" = "x" ; then + HAVE_FIG2DEV_PNG=yes + fi + fi + HAVE_FIG2DEV_PDF=no + if test "x$HAVE_FIG2DEV" = "xyes" ; then + fig2dev_quiet=`fig2dev -L pdf &1 >/dev/null` + if test "x$fig2dev_quiet" = "x" ; then + HAVE_FIG2DEV_PDF=yes + fi + fi + + AC_CHECK_PROG(HAVE_PNGTOPNM, pngtopnm, yes, no) + AC_CHECK_PROG(HAVE_PNMTOPS, pnmtops, yes, no) + AC_CHECK_PROG(HAVE_EPSTOPDF, epstopdf, yes, no) + + dnl check if we can generate HTML + if test "x$HAVE_DOCBOOK2HTML" = "xyes" && \ + test "x$enable_docbook" = "xyes" && \ + test "x$HAVE_XMLLINT" = "xyes" && \ + test "x$HAVE_FIG2DEV_PNG" = "xyes"; then + DOC_HTML=yes + AC_MSG_NOTICE(Will output HTML documentation) + else + DOC_HTML=no + AC_MSG_NOTICE(Will not output HTML documentation) + fi + + dnl check if we can generate PS + if test "x$HAVE_DOCBOOK2PS" = "xyes" && \ + test "x$enable_docbook" = "xyes" && \ + test "x$HAVE_XMLLINT" = "xyes" && \ + test "x$HAVE_JADETEX" = "xyes" && \ + test "x$HAVE_FIG2DEV_EPS" = "xyes" && \ + test "x$HAVE_DVIPS" = "xyes" && \ + test "x$HAVE_PNGTOPNM" = "xyes" && \ + test "x$HAVE_PNMTOPS" = "xyes"; then + DOC_PS=yes + AC_MSG_NOTICE(Will output PS documentation) + else + DOC_PS=no + AC_MSG_NOTICE(Will not output PS documentation) + fi + + dnl check if we can generate PDF - using only ps2pdf + if test "x$DOC_PS" = "xyes" && \ + test "x$enable_docbook" = "xyes" && \ + test "x$HAVE_XMLLINT" = "xyes" && \ + test "x$HAVE_PS2PDF" = "xyes"; then + DOC_PDF=yes + AC_MSG_NOTICE(Will output PDF documentation) + else + DOC_PDF=no + AC_MSG_NOTICE(Will not output PDF documentation) + fi + + dnl if we don't have everything, we should disable + if test "x$have_docbook" != "xyes"; then + enable_docbook=no + fi + fi + + dnl if we're going to install documentation, tell us where + if test "x$have_docbook" = "xyes"; then + AC_MSG_NOTICE(Installing documentation in $docdir) + AC_SUBST(docdir) + fi + + AM_CONDITIONAL(ENABLE_DOCBOOK, test x$enable_docbook = xyes) + AM_CONDITIONAL(DOC_HTML, test x$DOC_HTML = xyes) + AM_CONDITIONAL(DOC_PDF, test x$DOC_PDF = xyes) + AM_CONDITIONAL(DOC_PS, test x$DOC_PS = xyes) +]) diff --git a/common/m4/gst-error.m4 b/common/m4/gst-error.m4 new file mode 100755 index 0000000..f97f9a6 --- /dev/null +++ b/common/m4/gst-error.m4 @@ -0,0 +1,145 @@ +Dnl handle various error-related things + +dnl Thomas Vander Stichele +dnl Tim-Philipp Müller + +dnl Last modification: 2008-02-18 + +dnl AG_GST_SET_ERROR_CFLAGS([ADD-WERROR]) +dnl AG_GST_SET_ERROR_CXXFLAGS([ADD-WERROR]) +dnl AG_GST_SET_LEVEL_DEFAULT([IS-CVS-VERSION]) + + +dnl Sets ERROR_CFLAGS to something the compiler will accept. +dnl AC_SUBST them so they are available in Makefile + +dnl -Wall is added if it is supported +dnl -Werror is added if ADD-WERROR is not "no" + +dnl These flags can be overridden at make time: +dnl make ERROR_CFLAGS= +AC_DEFUN([AG_GST_SET_ERROR_CFLAGS], +[ + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AS_COMPILER_FLAG]) + + + dnl if we support -Wall, set it unconditionally + AS_COMPILER_FLAG(-Wall, + ERROR_CFLAGS="-Wall", + ERROR_CFLAGS="") + + dnl if asked for, add -Werror if supported + if test "x$1" != "xno" + then + AS_COMPILER_FLAG(-Werror, ERROR_CFLAGS="$ERROR_CFLAGS -Werror") + + dnl if -Werror isn't suported, try -errwarn=%all (Sun Forte case) + if test "x$ERROR_CFLAGS" == "x" + then + AS_COMPILER_FLAG([-errwarn=%all], [ + ERROR_CFLAGS="-errwarn=%all" + dnl try -errwarn=%all,no%E_EMPTY_DECLARATION, + dnl no%E_STATEMENT_NOT_REACHED,no%E_ARGUEMENT_MISMATCH, + dnl no%E_MACRO_REDEFINED (Sun Forte case) + dnl For Forte we need disable "empty declaration" warning produced by un-needed semicolon + dnl "statement not reached" disabled because there is g_assert_not_reached () in some places + dnl "macro redefined" because of gst/gettext.h + dnl FIXME: is it really supposed to be 'ARGUEMENT' and not 'ARGUMENT'? + for f in 'no%E_EMPTY_DECLARATION' \ + 'no%E_STATEMENT_NOT_REACHED' \ + 'no%E_ARGUEMENT_MISMATCH' \ + 'no%E_MACRO_REDEFINED' + do + AS_COMPILER_FLAG([-errwarn=%all,$f], [ + ERROR_CFLAGS="$ERROR_CFLAGS,$f" + ]) + done + ]) + fi + fi + + AC_SUBST(ERROR_CFLAGS) + AC_MSG_NOTICE([set ERROR_CFLAGS to $ERROR_CFLAGS]) +]) + +dnl Sets ERROR_CXXFLAGS to something the compiler will accept. +dnl AC_SUBST them so they are available in Makefile + +dnl -Wall is added if it is supported +dnl -Werror is added if ADD-WERROR is not "no" + +dnl These flags can be overridden at make time: +dnl make ERROR_CXXFLAGS= +AC_DEFUN([AG_GST_SET_ERROR_CXXFLAGS], +[ + AC_REQUIRE([AC_PROG_CXX]) + AC_REQUIRE([AS_CXX_COMPILER_FLAG]) + + + dnl if we support -Wall, set it unconditionally + AS_CXX_COMPILER_FLAG(-Wall, [ + ERROR_CXXFLAGS="-Wall" + ], [ + ERROR_CXXFLAGS="" + ]) + + dnl if asked for, add -Werror if supported + if test "x$1" != "xno" + then + AS_CXX_COMPILER_FLAG(-Werror, werror_supported=yes, werror_supported=no) + + if test "x$werror_supported" = "xyes"; then + ERROR_CXXFLAGS="$ERROR_CXXFLAGS -Werror" + + dnl add exceptions + for f in '-Wno-non-virtual-dtor' + do + AS_CXX_COMPILER_FLAG([$f], ERROR_CXXFLAGS="$ERROR_CXXFLAGS $f") + done + else + dnl if -Werror isn't suported, try -errwarn=%all + AS_CXX_COMPILER_FLAG([-errwarn=%all], errwarnall=yes, errwarnall=no) + if test "x$errwarnall" = "xyes"; then + ERROR_CXXFLAGS="-errwarn=%all" + dnl try -errwarn=%all,no%E_EMPTY_DECLARATION, + dnl no%E_STATEMENT_NOT_REACHED,no%E_ARGUEMENT_MISMATCH, + dnl no%E_MACRO_REDEFINED (Sun Forte case) + dnl For Forte we need disable "empty declaration" warning produced by un-needed semicolon + dnl "statement not reached" disabled because there is g_assert_not_reached () in some places + dnl "macro redefined" because of gst/gettext.h + dnl FIXME: is it really supposed to be 'ARGUEMENT' and not 'ARGUMENT'? + dnl FIXME: do any of these work with the c++ compiler? if not, why + dnl do we check at all? + for f in 'no%E_EMPTY_DECLARATION' \ + 'no%E_STATEMENT_NOT_REACHED' \ + 'no%E_ARGUEMENT_MISMATCH' \ + 'no%E_MACRO_REDEFINED' + do + AS_CXX_COMPILER_FLAG([-errwarn=%all,$f], [ + ERROR_CXXFLAGS="$ERROR_CXXFLAGS,$f" + ]) + done + fi + fi + fi + + AC_SUBST(ERROR_CXXFLAGS) + AC_MSG_NOTICE([set ERROR_CXXFLAGS to $ERROR_CXXFLAGS]) +]) + +dnl Sets the default error level for debugging messages +AC_DEFUN([AG_GST_SET_LEVEL_DEFAULT], +[ + dnl define correct errorlevel for debugging messages. We want to have + dnl GST_ERROR messages printed when running cvs builds + if test "x[$1]" = "xyes"; then + GST_LEVEL_DEFAULT=GST_LEVEL_ERROR + else + GST_LEVEL_DEFAULT=GST_LEVEL_NONE + fi + AC_DEFINE_UNQUOTED(GST_LEVEL_DEFAULT, $GST_LEVEL_DEFAULT, + [Default errorlevel to use]) + dnl AC_SUBST so we can use it for win32/common/config.h + AC_SUBST(GST_LEVEL_DEFAULT) +]) diff --git a/common/m4/gst-feature.m4 b/common/m4/gst-feature.m4 new file mode 100755 index 0000000..c7fe156 --- /dev/null +++ b/common/m4/gst-feature.m4 @@ -0,0 +1,286 @@ +dnl Perform a check for a feature for GStreamer +dnl Richard Boulton +dnl Thomas Vander Stichele added useful stuff +dnl Last modification: 25/06/2001 +dnl +dnl AG_GST_CHECK_FEATURE(FEATURE-NAME, FEATURE-DESCRIPTION, +dnl DEPENDENT-PLUGINS, TEST-FOR-FEATURE, +dnl DISABLE-BY-DEFAULT, ACTION-IF-USE, ACTION-IF-NOTUSE) +dnl +dnl This macro adds a command line argument to allow the user to enable +dnl or disable a feature, and if the feature is enabled, performs a supplied +dnl test to check if the feature is available. +dnl +dnl The test should define HAVE_ to "yes" or "no" depending +dnl on whether the feature is available. +dnl +dnl The macro will set USE_ to "yes" or "no" depending on +dnl whether the feature is to be used. +dnl Thomas changed this, so that when USE_ was already set +dnl to no, then it stays that way. +dnl +dnl The macro will call AM_CONDITIONAL(USE_, ...) to allow +dnl the feature to control what is built in Makefile.ams. If you want +dnl additional actions resulting from the test, you can add them with the +dnl ACTION-IF-USE and ACTION-IF-NOTUSE parameters. +dnl +dnl FEATURE-NAME is the name of the feature, and should be in +dnl purely upper case characters. +dnl FEATURE-DESCRIPTION is used to describe the feature in help text for +dnl the command line argument. +dnl DEPENDENT-PLUGINS lists any plug-ins which depend on this feature. +dnl TEST-FOR-FEATURE is a test which sets HAVE_ to "yes" +dnl or "no" depending on whether the feature is +dnl available. +dnl DISABLE-BY-DEFAULT if "disabled", the feature is disabled by default, +dnl if any other value, the feature is enabled by default. +dnl ACTION-IF-USE any extra actions to perform if the feature is to be +dnl used. +dnl ACTION-IF-NOTUSE any extra actions to perform if the feature is not to +dnl be used. +dnl +dnl +dnl thomas : +dnl we also added a history. +dnl GST_PLUGINS_YES will contain all plugins to be built +dnl that were checked through AG_GST_CHECK_FEATURE +dnl GST_PLUGINS_NO will contain those that won't be built + +AC_DEFUN([AG_GST_CHECK_FEATURE], +[echo +AC_MSG_NOTICE(*** checking feature: [$2] ***) +if test "x[$3]" != "x" +then + AC_MSG_NOTICE(*** for plug-ins: [$3] ***) +fi +dnl +builtin(define, [gst_endisable], ifelse($5, [disabled], [enable], [disable]))dnl +dnl if it is set to NO, then don't even consider it for building +NOUSE= +if test "x$USE_[$1]" = "xno"; then + NOUSE="yes" +fi +AC_ARG_ENABLE(translit([$1], A-Z, a-z), + [ ]builtin(format, --%-26s gst_endisable %s, gst_endisable-translit([$1], A-Z, a-z), [$2]ifelse([$3],,,: [$3])), + [ case "${enableval}" in + yes) USE_[$1]=yes;; + no) USE_[$1]=no;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-translit([$1], A-Z, a-z)) ;; + esac], + [ USE_$1=]ifelse($5, [disabled], [no], [yes])) dnl DEFAULT + +dnl *** set it back to no if it was preset to no +if test "x$NOUSE" = "xyes"; then + USE_[$1]="no" + AC_MSG_WARN(*** $3 pre-configured not to be built) +fi +NOUSE= + +dnl *** If it's enabled + +if test x$USE_[$1] = xyes; then + dnl save compile variables before the test + + gst_check_save_LIBS=$LIBS + gst_check_save_LDFLAGS=$LDFLAGS + gst_check_save_CFLAGS=$CFLAGS + gst_check_save_CPPFLAGS=$CPPFLAGS + gst_check_save_CXXFLAGS=$CXXFLAGS + + HAVE_[$1]=no + dnl TEST_FOR_FEATURE + $4 + + LIBS=$gst_check_save_LIBS + LDFLAGS=$gst_check_save_LDFLAGS + CFLAGS=$gst_check_save_CFLAGS + CPPFLAGS=$gst_check_save_CPPFLAGS + CXXFLAGS=$gst_check_save_CXXFLAGS + + dnl If it isn't found, unset USE_[$1] + if test x$HAVE_[$1] = xno; then + USE_[$1]=no + else + ifelse([$3], , :, [AC_MSG_NOTICE(*** These plugins will be built: [$3])]) + fi +fi +dnl *** Warn if it's disabled or not found +if test x$USE_[$1] = xyes; then + ifelse([$6], , :, [$6]) + if test "x$3" != "x"; then + GST_PLUGINS_YES="\t[$3]\n$GST_PLUGINS_YES" + fi + AC_DEFINE(HAVE_[$1], , [Define to enable $2]ifelse($3,,, [ (used by $3)]).) +else + ifelse([$3], , :, [AC_MSG_NOTICE(*** These plugins will not be built: [$3])]) + if test "x$3" != "x"; then + GST_PLUGINS_NO="\t[$3]\n$GST_PLUGINS_NO" + fi + ifelse([$7], , :, [$7]) +fi +dnl *** Define the conditional as appropriate +AM_CONDITIONAL(USE_[$1], test x$USE_[$1] = xyes) +]) + +dnl Use a -config program which accepts --cflags and --libs parameters +dnl to set *_CFLAGS and *_LIBS and check existence of a feature. +dnl Richard Boulton +dnl Last modification: 26/06/2001 +dnl AG_GST_CHECK_CONFIGPROG(FEATURE-NAME, CONFIG-PROG-FILENAME, MODULES) +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([AG_GST_CHECK_CONFIGPROG], +[ + AC_PATH_PROG([$1]_CONFIG, [$2], no) + if test x$[$1]_CONFIG = xno; then + [$1]_LIBS= + [$1]_CFLAGS= + HAVE_[$1]=no + else + if [$2] --plugin-libs [$3] &> /dev/null; then + [$1]_LIBS=`[$2] --plugin-libs [$3]` + else + [$1]_LIBS=`[$2] --libs [$3]` + fi + [$1]_CFLAGS=`[$2] --cflags [$3]` + HAVE_[$1]=yes + fi + AC_SUBST([$1]_LIBS) + AC_SUBST([$1]_CFLAGS) +]) + +dnl Use AC_CHECK_LIB and AC_CHECK_HEADER to do both tests at once +dnl sets HAVE_module if we have it +dnl Richard Boulton +dnl Last modification: 26/06/2001 +dnl AG_GST_CHECK_LIBHEADER(FEATURE-NAME, LIB NAME, LIB FUNCTION, EXTRA LD FLAGS, +dnl HEADER NAME, ACTION-IF-FOUND, ACTION-IF-NOT-FOUND) +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([AG_GST_CHECK_LIBHEADER], +[ + AC_CHECK_LIB([$2], [$3], HAVE_[$1]=yes, HAVE_[$1]=no,[$4]) + if test "x$HAVE_[$1]" = "xyes"; then + AC_CHECK_HEADER([$5], :, HAVE_[$1]=no) + if test "x$HAVE_[$1]" = "xyes"; then + dnl execute what needs to be + ifelse([$6], , :, [$6]) + else + ifelse([$7], , :, [$7]) + fi + else + ifelse([$7], , :, [$7]) + fi + AC_SUBST(HAVE_[$1]) +] +) + +dnl 2004-02-14 Thomas - changed to get set properly and use proper output +dnl 2003-06-27 Benjamin Otte - changed to make this work with gstconfig.h +dnl +dnl Add a subsystem --disable flag and all the necessary symbols and substitions +dnl +dnl AG_GST_CHECK_SUBSYSTEM_DISABLE(SYSNAME, [subsystem name]) +dnl +AC_DEFUN([AG_GST_CHECK_SUBSYSTEM_DISABLE], +[ + dnl this define will replace each literal subsys_def occurrence with + dnl the lowercase hyphen-separated subsystem + dnl e.g. if $1 is GST_DEBUG then subsys_def will be a macro with gst-debug + define([subsys_def],translit([$1], _A-Z, -a-z)) + + AC_ARG_ENABLE(subsys_def, + AC_HELP_STRING(--disable-subsys_def, [disable $2]), + [ + case "${enableval}" in + yes) GST_DISABLE_[$1]=no ;; + no) GST_DISABLE_[$1]=yes ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-subsys_def]) ;; + esac + ], + [GST_DISABLE_[$1]=no]) dnl Default value + + if test x$GST_DISABLE_[$1] = xyes; then + AC_MSG_NOTICE([disabled subsystem [$2]]) + GST_DISABLE_[$1]_DEFINE="#define GST_DISABLE_$1 1" + else + GST_DISABLE_[$1]_DEFINE="/* #undef GST_DISABLE_$1 */" + fi + AC_SUBST(GST_DISABLE_[$1]_DEFINE) + undefine([subsys_def]) +]) + + +dnl Parse gstconfig.h for feature and defines add the symbols and substitions +dnl +dnl AG_GST_PARSE_SUBSYSTEM_DISABLE(GST_CONFIGPATH, FEATURE) +dnl +AC_DEFUN([AG_GST_PARSE_SUBSYSTEM_DISABLE], +[ + grep >/dev/null "#undef GST_DISABLE_$2" $1 + if test $? = 0; then + GST_DISABLE_[$2]=0 + else + GST_DISABLE_[$2]=1 + fi + AC_SUBST(GST_DISABLE_[$2]) +]) + +dnl Parse gstconfig.h and defines add the symbols and substitions +dnl +dnl GST_CONFIGPATH=`$PKG_CONFIG --variable=includedir gstreamer-1.0`"/gst/gstconfig.h" +dnl AG_GST_PARSE_SUBSYSTEM_DISABLES(GST_CONFIGPATH) +dnl +AC_DEFUN([AG_GST_PARSE_SUBSYSTEM_DISABLES], +[ + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,GST_DEBUG) + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,LOADSAVE) + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,PARSE) + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,TRACE) + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,ALLOC_TRACE) + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,REGISTRY) + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,ENUMTYPES) + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,INDEX) + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,PLUGIN) + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,URI) + AG_GST_PARSE_SUBSYSTEM_DISABLE($1,XML) +]) + + + +dnl relies on GST_PLUGINS_ALL, GST_PLUGINS_SELECTED, GST_PLUGINS_YES, +dnl GST_PLUGINS_NO, and BUILD_EXTERNAL +AC_DEFUN([AG_GST_OUTPUT_PLUGINS], [ + +printf "configure: *** Plug-ins without external dependencies that will be built:\n" +( for i in $GST_PLUGINS_SELECTED; do printf '\t'$i'\n'; done ) | sort +printf "\n" + +printf "configure: *** Plug-ins without external dependencies that will NOT be built:\n" +( for i in $GST_PLUGINS_ALL; do + case $GST_PLUGINS_SELECTED in + *$i*) + ;; + *) + printf '\t'$i'\n' + ;; + esac + done ) | sort +printf "\n" + +if test "x$BUILD_EXTERNAL" = "xno"; then + printf "configure: *** No plug-ins with external dependencies will be built\n" +else + printf "configure: *** Plug-ins with dependencies that will be built:" + printf "$GST_PLUGINS_YES\n" | sort + printf "\n" + printf "configure: *** Plug-ins with dependencies that will NOT be built:" + printf "$GST_PLUGINS_NO\n" | sort + printf "\n" +fi +]) + diff --git a/common/m4/gst-function.m4 b/common/m4/gst-function.m4 new file mode 100755 index 0000000..1216621 --- /dev/null +++ b/common/m4/gst-function.m4 @@ -0,0 +1,63 @@ +dnl +dnl Check for compiler mechanism to show functions in debugging +dnl copied from an Ali patch floating on the internet +dnl +AC_DEFUN([AG_GST_CHECK_FUNCTION],[ + dnl #1: __PRETTY_FUNCTION__ + AC_MSG_CHECKING(whether $CC implements __PRETTY_FUNCTION__) + AC_CACHE_VAL(have_pretty_function,[ + AC_TRY_LINK([#include ], + [printf("%s", __PRETTY_FUNCTION__);], + have_pretty_function=yes, + have_pretty_function=no) + ]) + AC_MSG_RESULT($have_pretty_function) + if test "$have_pretty_function" = yes; then + AC_DEFINE(HAVE_PRETTY_FUNCTION, 1, + [defined if the compiler implements __PRETTY_FUNCTION__]) + fi + +dnl #2: __FUNCTION__ + AC_MSG_CHECKING(whether $CC implements __FUNCTION__) + AC_CACHE_VAL(have_function,[ + AC_TRY_LINK([#include ], + [printf("%s", __FUNCTION__);], + have_function=yes, + have_function=no) + ]) + AC_MSG_RESULT($have_function) + if test "$have_function" = yes; then + AC_DEFINE(HAVE_FUNCTION, 1, + [defined if the compiler implements __FUNCTION__]) + fi + +dnl #3: __func__ + AC_MSG_CHECKING(whether $CC implements __func__) + AC_CACHE_VAL(have_func,[ + AC_TRY_LINK([#include ], + [printf("%s", __func__);], + have_func=yes, + have_func=no) + ]) + AC_MSG_RESULT($have_func) + if test "$have_func" = yes; then + AC_DEFINE(HAVE_FUNC, 1, + [defined if the compiler implements __func__]) + fi + +dnl now define FUNCTION to whatever works, and fallback to "" + if test "$have_pretty_function" = yes; then + function=__PRETTY_FUNCTION__ + else + if test "$have_function" = yes; then + function=__FUNCTION__ + else + if test "$have_func" = yes; then + function=__func__ + else + function=\"\" + fi + fi + fi + AC_DEFINE_UNQUOTED(GST_FUNCTION, $function, [macro to use to show function name]) +]) diff --git a/common/m4/gst-gettext.m4 b/common/m4/gst-gettext.m4 new file mode 100755 index 0000000..a63651b --- /dev/null +++ b/common/m4/gst-gettext.m4 @@ -0,0 +1,21 @@ +dnl gettext setup + +dnl AG_GST_GETTEXT([gettext-package]) +dnl defines GETTEXT_PACKAGE and LOCALEDIR + +AC_DEFUN([AG_GST_GETTEXT], +[ + if test "$USE_NLS" = "yes"; then + GETTEXT_PACKAGE=[$1] + else + GETTEXT_PACKAGE=[NULL] + fi + AC_SUBST(GETTEXT_PACKAGE) + AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], "$GETTEXT_PACKAGE", + [gettext package name]) + + dnl define LOCALEDIR in config.h + AS_AC_EXPAND(LOCALEDIR, $datadir/locale) + AC_DEFINE_UNQUOTED([LOCALEDIR], "$LOCALEDIR", + [gettext locale dir]) +]) diff --git a/common/m4/gst-glib2.m4 b/common/m4/gst-glib2.m4 new file mode 100755 index 0000000..3060e5e --- /dev/null +++ b/common/m4/gst-glib2.m4 @@ -0,0 +1,25 @@ +dnl check for a minimum version of GLib + +dnl AG_GST_GLIB_CHECK([minimum-version-required]) + +AC_DEFUN([AG_GST_GLIB_CHECK], +[ + dnl Minimum required version of GLib + GLIB_REQ=[$1] + if test "x$GLIB_REQ" = "x" + then + AC_MSG_ERROR([Please specify a required version for GLib 2.0]) + fi + AC_SUBST(GLIB_REQ) + + dnl Check for glib with everything + AG_GST_PKG_CHECK_MODULES(GLIB, + glib-2.0 >= $GLIB_REQ gobject-2.0 gthread-2.0 gmodule-no-export-2.0) + + if test "x$HAVE_GLIB" = "xno"; then + AC_MSG_ERROR([This package requires GLib >= $GLIB_REQ to compile.]) + fi + + dnl for the poor souls who for example have glib in /usr/local + AS_SCRUB_INCLUDE(GLIB_CFLAGS) +]) diff --git a/common/m4/gst-libxml2.m4 b/common/m4/gst-libxml2.m4 new file mode 100755 index 0000000..7d978d3 --- /dev/null +++ b/common/m4/gst-libxml2.m4 @@ -0,0 +1,46 @@ +dnl call this macro with the minimum required version as an argument +dnl this macro sets and AC_SUBSTs XML_CFLAGS and XML_LIBS +dnl it also sets LIBXML_PKG, used for the pkg-config file + +AC_DEFUN([AG_GST_LIBXML2_CHECK], +[ + dnl Minimum required version of libxml2 + dnl default to 2.4.9 if not specified + LIBXML2_REQ=ifelse([$1],,2.4.9,[$1]) + AC_SUBST(LIBXML2_REQ) + + dnl check for libxml2 + PKG_CHECK_MODULES(XML, libxml-2.0 >= $LIBXML2_REQ, + HAVE_LIBXML2=yes, [ + AC_MSG_RESULT(no) + HAVE_LIBXML2=no + ]) + if test "x$HAVE_LIBXML2" = "xyes"; then + AC_DEFINE(HAVE_LIBXML2, 1, [Define if libxml2 is available]) + else + AC_MSG_ERROR([Need libxml2 for glib2 builds -- you should be able to do without it -- this needs fixing]) + fi + dnl this is for the .pc file + LIBXML_PKG=', libxml-2.0' + AC_SUBST(LIBXML_PKG) + AC_SUBST(XML_LIBS) + AC_SUBST(XML_CFLAGS) + + dnl XML_LIBS might pull in -lz without zlib actually being on the system, so + dnl try linking with these LIBS and CFLAGS + ac_save_CFLAGS=$CFLAGS + ac_save_LIBS=$LIBS + CFLAGS="$CFLAGS $XML_CFLAGS" + LIBS="$LIBS $XML_LIBS" + AC_TRY_LINK([ +#include +#include +],[ +/* function body */ +], + AC_MSG_NOTICE([Test xml2 program linked]), + AC_MSG_ERROR([Could not link libxml2 test program. Check if you have the necessary dependencies.]) + ) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" +]) diff --git a/common/m4/gst-parser.m4 b/common/m4/gst-parser.m4 new file mode 100755 index 0000000..9cc0981 --- /dev/null +++ b/common/m4/gst-parser.m4 @@ -0,0 +1,63 @@ +AC_DEFUN([AG_GST_BISON_CHECK], +[ + dnl FIXME: check if AC_PROG_YACC is suitable here + dnl FIXME: make precious + AC_PATH_PROG(BISON_PATH, bison, no) + if test x$BISON_PATH = xno; then + AC_MSG_ERROR(Could not find bison) + fi + + dnl check bison version + dnl FIXME 0.11: we need version >= 1.875 for the reentrancy support + dnl in the parser. If an older version is installed pre-generated + dnl sources are used. This should become a hard dependency for 0.11! + bison_min_version=1.875 + bison_version=`$BISON_PATH --version | head -n 1 | sed 's/^.*) //' | sed 's/[[a-zA-Z]]*$//' | cut -d' ' -f1` + AC_MSG_CHECKING([bison version $bison_version >= $bison_min_version]) + + if perl -w <= 2.5.31 for the reentrancy support + dnl in the parser. If an older version is installed pre-generated + dnl sources are used. This should become a hard dependency for 0.11! + flex_min_version=2.5.31 + flex_version=`$FLEX_PATH --version | head -n 1 | sed 's/^.* //' | sed 's/[[a-zA-Z]]*$//' | cut -d' ' -f1` + AC_MSG_CHECKING([flex version $flex_version >= $flex_min_version]) + if perl -w < \$min_version_major) || + ((\$flex_version_major == \$min_version_major) && + (\$flex_version_minor > \$min_version_minor)) || + ((\$flex_version_major == \$min_version_major) && + (\$flex_version_minor == \$min_version_minor) && + (\$flex_version_micro >= \$min_version_micro))) + ? 0 : 1); +EOF + then + AC_MSG_RESULT(yes) + AM_CONDITIONAL(GENERATE_PARSER, test -z $GENERATE_PARSER_TRUE) + else + AC_MSG_RESULT([no, using pre-generated parser sources]) + AM_CONDITIONAL(GENERATE_PARSER, false) + fi +]) diff --git a/common/m4/gst-plugin-docs.m4 b/common/m4/gst-plugin-docs.m4 new file mode 100755 index 0000000..29ebbd6 --- /dev/null +++ b/common/m4/gst-plugin-docs.m4 @@ -0,0 +1,47 @@ +dnl AG_GST_PYXML_CHECK([MINIMUM-PYTHON-VERSION]) + +AC_DEFUN([AG_GST_PYXML_CHECK], +[ + AC_BEFORE([AS_PATH_PYTHON],[$0])dnl find python first + + have_pyxml=no + if test "x$PYTHON" != x; then + AC_MSG_CHECKING([pyxml]) + if $PYTHON -c "from xml.dom.ext.reader import Sax2" 2>/dev/null \ + && $PYTHON -c "from xml.dom.NodeFilter import NodeFilter" 2>/dev/null; then + AC_MSG_RESULT(yes) + have_pyxml=yes + else + AC_MSG_RESULT(no) + fi + fi +]) + +dnl AG_GST_PLUGIN_DOCS([MINIMUM-GTK-DOC-VERSION],[MINIMUM-PYTHON-VERSION]) +dnl +dnl checks for prerequisites for the common/mangle-tmpl.py script +dnl used when building the plugin documentation + +AC_DEFUN([AG_GST_PLUGIN_DOCS], +[ + AC_BEFORE([GTK_DOC_CHECK],[$0])dnl check for gtk-doc first + + if test x$enable_gtk_doc = xyes -a x$have_gtk_doc = xyes; then + AG_GST_PYXML_CHECK([$1]) + fi + + build_plugin_docs=no + AC_MSG_CHECKING([whether to build plugin documentation]) + if test x$enable_gtk_doc = xyes -a x$have_gtk_doc = xyes; then + if test "x$have_pyxml" != xyes; then + AC_MSG_RESULT([no (pyxml not installed)]) + else + build_plugin_docs=yes + AC_MSG_RESULT([yes]) + fi + else + AC_MSG_RESULT([no (gtk-doc disabled or not available)]) + fi + + AM_CONDITIONAL(ENABLE_PLUGIN_DOCS, test x$build_plugin_docs = xyes) +]) diff --git a/common/m4/gst-plugindir.m4 b/common/m4/gst-plugindir.m4 new file mode 100755 index 0000000..09989d0 --- /dev/null +++ b/common/m4/gst-plugindir.m4 @@ -0,0 +1,17 @@ +dnl AG_GST_SET_PLUGINDIR + +dnl AC_DEFINE PLUGINDIR to the full location where plug-ins will be installed +dnl AC_SUBST plugindir, to be used in Makefile.am's + +AC_DEFUN([AG_GST_SET_PLUGINDIR], +[ + dnl define location of plugin directory + AS_AC_EXPAND(PLUGINDIR, ${libdir}/gstreamer-$GST_MAJORMINOR) + AC_DEFINE_UNQUOTED(PLUGINDIR, "$PLUGINDIR", + [directory where plugins are located]) + AC_MSG_NOTICE([Using $PLUGINDIR as the plugin install location]) + + dnl plugin directory configure-time variable for use in Makefile.am + plugindir="\$(libdir)/gstreamer-$GST_MAJORMINOR" + AC_SUBST(plugindir) +]) diff --git a/common/m4/gst-valgrind.m4 b/common/m4/gst-valgrind.m4 new file mode 100755 index 0000000..93c2635 --- /dev/null +++ b/common/m4/gst-valgrind.m4 @@ -0,0 +1,35 @@ +AC_DEFUN([AG_GST_VALGRIND_CHECK], +[ + dnl valgrind inclusion + AC_ARG_ENABLE(valgrind, + AC_HELP_STRING([--disable-valgrind], [disable run-time valgrind detection]), + [ + case "${enableval}" in + yes) USE_VALGRIND="$USE_DEBUG" ;; + no) USE_VALGRIND=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-valgrind) ;; + esac], + [ + USE_VALGRIND="$USE_DEBUG" + ]) dnl Default value + + VALGRIND_REQ="2.1" + if test "x$USE_VALGRIND" = xyes; then + PKG_CHECK_MODULES(VALGRIND, valgrind > $VALGRIND_REQ, + USE_VALGRIND="yes", + [ + USE_VALGRIND="no" + AC_MSG_RESULT([no]) + ]) + fi + + if test "x$USE_VALGRIND" = xyes; then + AC_DEFINE(HAVE_VALGRIND, 1, [Define if valgrind should be used]) + AC_MSG_NOTICE(Using extra code paths for valgrind) + fi + AC_SUBST(VALGRIND_CFLAGS) + AC_SUBST(VALGRIND_LIBS) + + AC_PATH_PROG(VALGRIND_PATH, valgrind, no) + AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno") +]) diff --git a/common/m4/gst-x11.m4 b/common/m4/gst-x11.m4 new file mode 100644 index 0000000..d3baf2d --- /dev/null +++ b/common/m4/gst-x11.m4 @@ -0,0 +1,70 @@ +dnl macros for X-related detections +dnl AC_SUBST's HAVE_X, X_CFLAGS, X_LIBS +AC_DEFUN([AG_GST_CHECK_X], +[ + AC_PATH_XTRA + ac_cflags_save="$CFLAGS" + ac_cppflags_save="$CPPFLAGS" + CFLAGS="$CFLAGS $X_CFLAGS" + CPPFLAGS="$CPPFLAGS $X_CFLAGS" + + dnl now try to find the HEADER + AC_CHECK_HEADER(X11/Xlib.h, HAVE_X="yes", HAVE_X="no") + + if test "x$HAVE_X" = "xno" + then + AC_MSG_NOTICE([cannot find X11 development files]) + else + dnl this is much more than we want + X_LIBS="$X_LIBS $X_PRE_LIBS $X_EXTRA_LIBS" + dnl AC_PATH_XTRA only defines the path needed to find the X libs, + dnl it does not add the libs; therefore we add them here + X_LIBS="$X_LIBS -lX11" + AC_SUBST(X_CFLAGS) + AC_SUBST(X_LIBS) + fi + AC_SUBST(HAVE_X) + + CFLAGS="$ac_cflags_save" + CPPFLAGS="$ac_cppflags_save" +]) + +dnl *** XVideo *** +dnl Look for the PIC library first, Debian requires it. +dnl Check debian-devel archives for gory details. +dnl 20020110: +dnl At the moment XFree86 doesn't distribute shared libXv due +dnl to unstable API. On many platforms you CAN NOT link a shared +dnl lib to a static non-PIC lib. This is what the xvideo GStreamer +dnl plug-in wants to do. So Debian distributes a PIC compiled +dnl version of the static lib for plug-ins to link to when it is +dnl inappropriate to link the main application to libXv directly. +dnl FIXME: add check if this platform can support linking to a +dnl non-PIC libXv, if not then don not use Xv. +dnl FIXME: perhaps warn user if they have a shared libXv since +dnl this is an error until XFree86 starts shipping one +AC_DEFUN([AG_GST_CHECK_XV], +[ + if test x$HAVE_X = xyes; then + AC_CHECK_LIB(Xv_pic, XvQueryExtension, + HAVE_XVIDEO="yes", HAVE_XVIDEO="no", + $X_LIBS -lXext) + + if test x$HAVE_XVIDEO = xyes; then + XVIDEO_LIBS="-lXv_pic -lXext" + AC_SUBST(XVIDEO_LIBS) + else + dnl try again using something else if we didn't find it first + if test x$HAVE_XVIDEO = xno; then + AC_CHECK_LIB(Xv, XvQueryExtension, + HAVE_XVIDEO="yes", HAVE_XVIDEO="no", + $X_LIBS -lXext) + + if test x$HAVE_XVIDEO = xyes; then + XVIDEO_LIBS="-lXv -lXext" + AC_SUBST(XVIDEO_LIBS) + fi + fi + fi + fi +]) diff --git a/common/m4/gst.m4 b/common/m4/gst.m4 new file mode 100755 index 0000000..04b466f --- /dev/null +++ b/common/m4/gst.m4 @@ -0,0 +1,10 @@ +dnl AG_GST_INIT +dnl sets up use of GStreamer configure.ac macros +dnl all GStreamer autoconf macros are prefixed +dnl with AG_GST_ for public macros +dnl with _AG_GST_ for private macros + +AC_DEFUN([AG_GST_INIT], +[ + m4_pattern_forbid(^_?AG_GST_) +]) diff --git a/common/m4/gtk-doc.m4 b/common/m4/gtk-doc.m4 new file mode 100755 index 0000000..57040aa --- /dev/null +++ b/common/m4/gtk-doc.m4 @@ -0,0 +1,56 @@ +dnl -*- mode: autoconf -*- + +# serial 1 + +dnl Usage: +dnl GTK_DOC_CHECK([minimum-gtk-doc-version]) +AC_DEFUN([GTK_DOC_CHECK], +[ + AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first + AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first + dnl for overriding the documentation installation directory + AC_ARG_WITH(html-dir, + AC_HELP_STRING([--with-html-dir=PATH], [path to installed docs]),, + [with_html_dir='${datadir}/gtk-doc/html']) + HTML_DIR="$with_html_dir" + AC_SUBST(HTML_DIR) + + dnl enable/disable documentation building + AC_ARG_ENABLE(gtk-doc, + AC_HELP_STRING([--enable-gtk-doc], + [use gtk-doc to build documentation [default=no]]),, + enable_gtk_doc=no) + + have_gtk_doc=no + if test x$enable_gtk_doc = xyes; then + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + if test "$PKG_CONFIG" != "no" && $PKG_CONFIG --exists gtk-doc; then + have_gtk_doc=yes + fi + if test -z "$SED"; then + AC_PROG_SED + fi + +dnl do we want to do a version check? +ifelse([$1],[],, + [gtk_doc_min_version=$1 + if test "$have_gtk_doc" = yes; then + AC_MSG_CHECKING([gtk-doc version >= $gtk_doc_min_version]) + if $PKG_CONFIG --atleast-version $gtk_doc_min_version gtk-doc; then + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + have_gtk_doc=no + fi + fi +]) + if test "$have_gtk_doc" != yes; then + enable_gtk_doc=no + fi + fi + + AM_CONDITIONAL(ENABLE_GTK_DOC, test x$enable_gtk_doc = xyes) + AM_CONDITIONAL(GTK_DOC_USE_LIBTOOL, test -n "$LIBTOOL") +]) diff --git a/common/m4/iconv.m4 b/common/m4/iconv.m4 new file mode 100755 index 0000000..c5f3579 --- /dev/null +++ b/common/m4/iconv.m4 @@ -0,0 +1,103 @@ +# iconv.m4 serial AM4 (gettext-0.11.3) +dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl From Bruno Haible. + +AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], +[ + dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + + dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV + dnl accordingly. + AC_LIB_LINKFLAGS_BODY([iconv]) +]) + +AC_DEFUN([AM_ICONV_LINK], +[ + dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and + dnl those with the standalone portable GNU libiconv installed). + + dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV + dnl accordingly. + AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) + + dnl Add $INCICONV to CPPFLAGS before performing the following checks, + dnl because if the user has installed libiconv and not disabled its use + dnl via --without-libiconv-prefix, he wants to use it. The first + dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed. + am_save_CPPFLAGS="$CPPFLAGS" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) + + AC_CACHE_CHECK(for iconv, am_cv_func_iconv, [ + am_cv_func_iconv="no, consider installing GNU libiconv" + am_cv_lib_iconv=no + AC_TRY_LINK([#include +#include ], + [iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd);], + am_cv_func_iconv=yes) + if test "$am_cv_func_iconv" != yes; then + am_save_LIBS="$LIBS" + LIBS="$LIBS $LIBICONV" + AC_TRY_LINK([#include +#include ], + [iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd);], + am_cv_lib_iconv=yes + am_cv_func_iconv=yes) + LIBS="$am_save_LIBS" + fi + ]) + if test "$am_cv_func_iconv" = yes; then + AC_DEFINE(HAVE_ICONV, 1, [Define if you have the iconv() function.]) + fi + if test "$am_cv_lib_iconv" = yes; then + AC_MSG_CHECKING([how to link with libiconv]) + AC_MSG_RESULT([$LIBICONV]) + else + dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV + dnl either. + CPPFLAGS="$am_save_CPPFLAGS" + LIBICONV= + LTLIBICONV= + fi + AC_SUBST(LIBICONV) + AC_SUBST(LTLIBICONV) +]) + +AC_DEFUN([AM_ICONV], +[ + AM_ICONV_LINK + if test "$am_cv_func_iconv" = yes; then + AC_MSG_CHECKING([for iconv declaration]) + AC_CACHE_VAL(am_cv_proto_iconv, [ + AC_TRY_COMPILE([ +#include +#include +extern +#ifdef __cplusplus +"C" +#endif +#if defined(__STDC__) || defined(__cplusplus) +size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); +#else +size_t iconv(); +#endif +], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const") + am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) + am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` + AC_MSG_RESULT([$]{ac_t:- + }[$]am_cv_proto_iconv) + AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1, + [Define as const if the declaration of iconv() needs const.]) + fi +]) diff --git a/common/m4/isc-posix.m4 b/common/m4/isc-posix.m4 new file mode 100755 index 0000000..1319dd1 --- /dev/null +++ b/common/m4/isc-posix.m4 @@ -0,0 +1,26 @@ +# isc-posix.m4 serial 2 (gettext-0.11.2) +dnl Copyright (C) 1995-2002 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +# This file is not needed with autoconf-2.53 and newer. Remove it in 2005. + +# This test replaces the one in autoconf. +# Currently this macro should have the same name as the autoconf macro +# because gettext's gettext.m4 (distributed in the automake package) +# still uses it. Otherwise, the use in gettext.m4 makes autoheader +# give these diagnostics: +# configure.in:556: AC_TRY_COMPILE was called before AC_ISC_POSIX +# configure.in:556: AC_TRY_RUN was called before AC_ISC_POSIX + +undefine([AC_ISC_POSIX]) + +AC_DEFUN([AC_ISC_POSIX], + [ + dnl This test replaces the obsolescent AC_ISC_POSIX kludge. + AC_CHECK_LIB(cposix, strerror, [LIBS="$LIBS -lcposix"]) + ] +) diff --git a/common/m4/lib-ld.m4 b/common/m4/lib-ld.m4 new file mode 100755 index 0000000..ddb5732 --- /dev/null +++ b/common/m4/lib-ld.m4 @@ -0,0 +1,97 @@ +# lib-ld.m4 serial 1 (gettext-0.11) +dnl Copyright (C) 1996-2002 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl Subroutines of libtool.m4, +dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision +dnl with libtool.m4. + +dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no. +AC_DEFUN([AC_LIB_PROG_LD_GNU], +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + acl_cv_prog_gnu_ld=yes +else + acl_cv_prog_gnu_ld=no +fi]) +with_gnu_ld=$acl_cv_prog_gnu_ld +]) + +dnl From libtool-1.4. Sets the variable LD. +AC_DEFUN([AC_LIB_PROG_LD], +[AC_ARG_WITH(gnu-ld, +[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], +test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]* | [A-Za-z]:[\\/]*)] + [re_direlt='/[^/][^/]*/\.\./'] + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(acl_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + acl_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$acl_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + acl_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$acl_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_LIB_PROG_LD_GNU +]) diff --git a/common/m4/lib-link.m4 b/common/m4/lib-link.m4 new file mode 100755 index 0000000..6b94251 --- /dev/null +++ b/common/m4/lib-link.m4 @@ -0,0 +1,554 @@ +# lib-link.m4 serial 3 (gettext-0.11.3) +dnl Copyright (C) 2001-2002 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl From Bruno Haible. + +dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and +dnl the libraries corresponding to explicit and implicit dependencies. +dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and +dnl augments the CPPFLAGS variable. +AC_DEFUN([AC_LIB_LINKFLAGS], +[ + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + define([Name],[translit([$1],[./-], [___])]) + define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ + AC_LIB_LINKFLAGS_BODY([$1], [$2]) + ac_cv_lib[]Name[]_libs="$LIB[]NAME" + ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" + ac_cv_lib[]Name[]_cppflags="$INC[]NAME" + ]) + LIB[]NAME="$ac_cv_lib[]Name[]_libs" + LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" + INC[]NAME="$ac_cv_lib[]Name[]_cppflags" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) + AC_SUBST([LIB]NAME) + AC_SUBST([LTLIB]NAME) + dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the + dnl results of this search when this library appears as a dependency. + HAVE_LIB[]NAME=yes + undefine([Name]) + undefine([NAME]) +]) + +dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode) +dnl searches for libname and the libraries corresponding to explicit and +dnl implicit dependencies, together with the specified include files and +dnl the ability to compile and link the specified testcode. If found, it +dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and +dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and +dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs +dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. +AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], +[ + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + define([Name],[translit([$1],[./-], [___])]) + define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + + dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME + dnl accordingly. + AC_LIB_LINKFLAGS_BODY([$1], [$2]) + + dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, + dnl because if the user has installed lib[]Name and not disabled its use + dnl via --without-lib[]Name-prefix, he wants to use it. + ac_save_CPPFLAGS="$CPPFLAGS" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) + + AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ + ac_save_LIBS="$LIBS" + LIBS="$LIBS $LIB[]NAME" + AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no]) + LIBS="$ac_save_LIBS" + ]) + if test "$ac_cv_lib[]Name" = yes; then + HAVE_LIB[]NAME=yes + AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.]) + AC_MSG_CHECKING([how to link with lib[]$1]) + AC_MSG_RESULT([$LIB[]NAME]) + else + HAVE_LIB[]NAME=no + dnl If $LIB[]NAME didn't lead to a usable library, we don't need + dnl $INC[]NAME either. + CPPFLAGS="$ac_save_CPPFLAGS" + LIB[]NAME= + LTLIB[]NAME= + fi + AC_SUBST([HAVE_LIB]NAME) + AC_SUBST([LIB]NAME) + AC_SUBST([LTLIB]NAME) + undefine([Name]) + undefine([NAME]) +]) + +dnl Determine the platform dependent parameters needed to use rpath: +dnl libext, shlibext, hardcode_libdir_flag_spec, hardcode_libdir_separator, +dnl hardcode_direct, hardcode_minus_L, +dnl sys_lib_search_path_spec, sys_lib_dlsearch_path_spec. +AC_DEFUN([AC_LIB_RPATH], +[ + AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS + AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld + AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host + AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir + AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [ + CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ + ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh + . ./conftest.sh + rm -f ./conftest.sh + acl_cv_rpath=done + ]) + wl="$acl_cv_wl" + libext="$acl_cv_libext" + shlibext="$acl_cv_shlibext" + hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" + hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" + hardcode_direct="$acl_cv_hardcode_direct" + hardcode_minus_L="$acl_cv_hardcode_minus_L" + sys_lib_search_path_spec="$acl_cv_sys_lib_search_path_spec" + sys_lib_dlsearch_path_spec="$acl_cv_sys_lib_dlsearch_path_spec" + dnl Determine whether the user wants rpath handling at all. + AC_ARG_ENABLE(rpath, + [ --disable-rpath do not hardcode runtime library paths], + :, enable_rpath=yes) +]) + +dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and +dnl the libraries corresponding to explicit and implicit dependencies. +dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. +AC_DEFUN([AC_LIB_LINKFLAGS_BODY], +[ + define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + dnl By default, look in $includedir and $libdir. + use_additional=yes + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + AC_ARG_WITH([lib$1-prefix], +[ --with-lib$1-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib + --without-lib$1-prefix don't search for lib$1 in includedir and libdir], +[ + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + else + additional_includedir="$withval/include" + additional_libdir="$withval/lib" + fi + fi +]) + dnl Search the library and its dependencies in $additional_libdir and + dnl $LDFLAGS. Using breadth-first-seach. + LIB[]NAME= + LTLIB[]NAME= + INC[]NAME= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='$1 $2' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + dnl See if it was already located by an earlier AC_LIB_LINKFLAGS + dnl or AC_LIB_HAVE_LINKFLAGS call. + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" + else + dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined + dnl that this library doesn't exist. So just drop it. + : + fi + else + dnl Search the library lib$name in $additional_libdir and $LDFLAGS + dnl and the already constructed $LIBNAME/$LTLIBNAME. + found_dir= + found_la= + found_so= + found_a= + if test $use_additional = yes; then + if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then + found_dir="$additional_libdir" + found_so="$additional_libdir/lib$name.$shlibext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + else + if test -f "$additional_libdir/lib$name.$libext"; then + found_dir="$additional_libdir" + found_a="$additional_libdir/lib$name.$libext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then + found_dir="$dir" + found_so="$dir/lib$name.$shlibext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + else + if test -f "$dir/lib$name.$libext"; then + found_dir="$dir" + found_a="$dir/lib$name.$libext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + dnl Found the library. + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + dnl Linking with a shared library. We attempt to hardcode its + dnl directory into the executable's runpath, unless it's the + dnl standard /usr/lib. + if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then + dnl No hardcoding is needed. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + dnl Use an explicit option to hardcode DIR into the resulting + dnl binary. + dnl Potentially add DIR to ltrpathdirs. + dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + dnl The hardcoding into $LIBNAME is system dependent. + if test "$hardcode_direct" = yes; then + dnl Using DIR/libNAME.so during linking hardcodes DIR into the + dnl resulting binary. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then + dnl Use an explicit option to hardcode DIR into the resulting + dnl binary. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + dnl Potentially add DIR to rpathdirs. + dnl The rpathdirs will be appended to $LIBNAME at the end. + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + dnl Rely on "-L$found_dir". + dnl But don't add it if it's already contained in the LDFLAGS + dnl or the already constructed $LIBNAME + haveit= + for x in $LDFLAGS $LIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" + fi + if test "$hardcode_minus_L" != no; then + dnl FIXME: Not sure whether we should use + dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" + dnl here. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + dnl We cannot use $hardcode_runpath_var and LD_RUN_PATH + dnl here, because this doesn't fit in flags passed to the + dnl compiler. So give up. No hardcoding. This affects only + dnl very old systems. + dnl FIXME: Not sure whether we should use + dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" + dnl here. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + dnl Linking with a static library. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" + else + dnl We shouldn't come here, but anyway it's good to have a + dnl fallback. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" + fi + fi + dnl Assume the include files are nearby. + additional_includedir= + case "$found_dir" in + */lib | */lib/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'` + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + dnl Potentially add $additional_includedir to $INCNAME. + dnl But don't add it + dnl 1. if it's the standard /usr/include, + dnl 2. if it's /usr/local/include and we are using GCC on Linux, + dnl 3. if it's already present in $CPPFLAGS or the already + dnl constructed $INCNAME, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INC[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + dnl Really add $additional_includedir to $INCNAME. + INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + dnl Look for dependencies. + if test -n "$found_la"; then + dnl Read the .la file. It defines the variables + dnl dlname, library_names, old_library, dependency_libs, current, + dnl age, revision, installed, dlopen, dlpreopen, libdir. + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + dnl We use only dependency_libs. + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. + dnl But don't add it + dnl 1. if it's the standard /usr/lib, + dnl 2. if it's /usr/local/lib and we are using GCC on Linux, + dnl 3. if it's already present in $LDFLAGS or the already + dnl constructed $LIBNAME, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_libdir" != "X/usr/lib"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/lib"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LIBNAME. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LTLIBNAME. + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + dnl Potentially add DIR to rpathdirs. + dnl The rpathdirs will be appended to $LIBNAME at the end. + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + dnl Potentially add DIR to ltrpathdirs. + dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + dnl Handle this in the next round. + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + dnl Handle this in the next round. Throw away the .la's + dnl directory; it is already contained in a preceding -L + dnl option. + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + dnl Most likely an immediate library name. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" + ;; + esac + done + fi + else + dnl Didn't find the library; assume it is in the system directories + dnl known to the linker and runtime loader. (All the system + dnl directories known to the linker should also be known to the + dnl runtime loader, otherwise the system is severely misconfigured.) + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$hardcode_libdir_separator"; then + dnl Weird platform: only the last -rpath option counts, the user must + dnl pass all path elements in one option. We can arrange that for a + dnl single library, but not when more than one $LIBNAMEs are used. + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" + done + dnl Note: hardcode_libdir_flag_spec uses $libdir and $wl. + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" + else + dnl The -rpath options are cumulative. + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + dnl When using libtool, the option that works for both libraries and + dnl executables is -R. The -R options are cumulative. + for found_dir in $ltrpathdirs; do + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" + done + fi +]) + +dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, +dnl unless already present in VAR. +dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes +dnl contains two or three consecutive elements that belong together. +AC_DEFUN([AC_LIB_APPENDTOVAR], +[ + for element in [$2]; do + haveit= + for x in $[$1]; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + [$1]="${[$1]}${[$1]:+ }$element" + fi + done +]) diff --git a/common/m4/lib-prefix.m4 b/common/m4/lib-prefix.m4 new file mode 100755 index 0000000..b8b79ab --- /dev/null +++ b/common/m4/lib-prefix.m4 @@ -0,0 +1,148 @@ +# lib-prefix.m4 serial 1 (gettext-0.11) +dnl Copyright (C) 2001-2002 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl From Bruno Haible. + +dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed +dnl to access previously installed libraries. The basic assumption is that +dnl a user will want packages to use other packages he previously installed +dnl with the same --prefix option. +dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate +dnl libraries, but is otherwise very convenient. +AC_DEFUN([AC_LIB_PREFIX], +[ + AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + dnl By default, look in $includedir and $libdir. + use_additional=yes + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + AC_ARG_WITH([lib-prefix], +[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib + --without-lib-prefix don't search for libraries in includedir and libdir], +[ + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + else + additional_includedir="$withval/include" + additional_libdir="$withval/lib" + fi + fi +]) + if test $use_additional = yes; then + dnl Potentially add $additional_includedir to $CPPFLAGS. + dnl But don't add it + dnl 1. if it's the standard /usr/include, + dnl 2. if it's already present in $CPPFLAGS, + dnl 3. if it's /usr/local/include and we are using GCC on Linux, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + for x in $CPPFLAGS; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + dnl Really add $additional_includedir to $CPPFLAGS. + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" + fi + fi + fi + fi + dnl Potentially add $additional_libdir to $LDFLAGS. + dnl But don't add it + dnl 1. if it's the standard /usr/lib, + dnl 2. if it's already present in $LDFLAGS, + dnl 3. if it's /usr/local/lib and we are using GCC on Linux, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_libdir" != "X/usr/lib"; then + haveit= + for x in $LDFLAGS; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test "X$additional_libdir" = "X/usr/local/lib"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LDFLAGS. + LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" + fi + fi + fi + fi + fi +]) + +dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, +dnl acl_final_exec_prefix, containing the values to which $prefix and +dnl $exec_prefix will expand at the end of the configure script. +AC_DEFUN([AC_LIB_PREPARE_PREFIX], +[ + dnl Unfortunately, prefix and exec_prefix get only finally determined + dnl at the end of configure. + if test "X$prefix" = "XNONE"; then + acl_final_prefix="$ac_default_prefix" + else + acl_final_prefix="$prefix" + fi + if test "X$exec_prefix" = "XNONE"; then + acl_final_exec_prefix='${prefix}' + else + acl_final_exec_prefix="$exec_prefix" + fi + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" + prefix="$acl_save_prefix" +]) + +dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the +dnl variables prefix and exec_prefix bound to the values they will have +dnl at the end of the configure script. +AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], +[ + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + $1 + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" +]) diff --git a/common/m4/libtool.m4 b/common/m4/libtool.m4 new file mode 100644 index 0000000..a3fee53 --- /dev/null +++ b/common/m4/libtool.m4 @@ -0,0 +1,7377 @@ +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool 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. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that 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. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +]) + +# serial 56 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +m4_defun([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl +_LT_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from `configure', and `config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# `config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain="$ac_aux_dir/ltmain.sh" +])# _LT_PROG_LTMAIN + + +## ------------------------------------- ## +## Accumulate code for creating libtool. ## +## ------------------------------------- ## + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the `libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + +## ------------------------ ## +## FIXME: Eliminate VARNAME ## +## ------------------------ ## + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to `config.status' so that its +# declaration there will have the same value as in `configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# ='`$ECHO "X$" | $Xsed -e "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags="_LT_TAGS"dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the `libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into `config.status', and then the shell code to quote escape them in +# for loops in `config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Fix-up fallback echo if it was mangled by the above quoting rules. +case \$lt_ECHO in +*'\\\[$]0 --fallback-echo"')dnl " + lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\` + ;; +esac + +_LT_OUTPUT_LIBTOOL_INIT +]) + + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +cat >"$CONFIG_LT" <<_LTEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate a libtool stub with the current configuration. + +lt_cl_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AS_SHELL_SANITIZE +_AS_PREPARE + +exec AS_MESSAGE_FD>&1 +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +\`$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to ." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2008 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test $[#] != 0 +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try \`$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try \`$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +if test "$no_create" != yes; then + lt_cl_success=: + test "$silent" = yes && + lt_config_lt_args="$lt_config_lt_args --quiet" + exec AS_MESSAGE_LOG_FD>/dev/null + $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false + exec AS_MESSAGE_LOG_FD>>config.log + $lt_cl_success || AS_EXIT(1) +fi +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, create an initial libtool script with a +# default configuration from the untagged config vars. Otherwise add code +# to config.status for appending the configuration named by TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +_LT_COPYING +_LT_LIBTOOL_TAGS + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + _LT_PROG_XSI_SHELLFNS + + sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS="$save_LDFLAGS" + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[[012]]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES +# -------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=echo + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + m4_if([$1], [CXX], +[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX +# ----------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_SHELL_INIT + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[_LT_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$lt_ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +ECHO=${lt_ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<_LT_EOF +[$]* +_LT_EOF + exit 0 +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test -z "$lt_ECHO"; then + if test "X${echo_test_string+set}" != Xset; then + # find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if { echo_test_string=`eval $cmd`; } 2>/dev/null && + { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null + then + break + fi + done + fi + + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : + else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$ECHO" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + ECHO='print -r' + elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + ECHO='printf %s\n' + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + ECHO="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + ECHO=echo + fi + fi + fi + fi + fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +lt_ECHO=$ECHO +if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(lt_ECHO) +]) +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], + [An echo program that does not interpret backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" +])# _LT_ENABLE_LOCK + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[AC_CHECK_TOOL(AR, ar, false) +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1]) + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $RM conftest* +]) + +if test x"[$]$2" = xyes; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ + = "XX$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line __oline__ "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links="nottested" +if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", + [Define to the sub-directory in which libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || + test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` + else + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[[4-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[123]]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[[3-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # Some binutils ld are patched to set DT_RUNPATH + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[List of archive names. First name is the real one, the rest are links. + The last name is the one that the linker finds with -lNAME]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([], [sys_lib_dlsearch_path_spec], [2], + [Run-time system search path for libraries]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program which can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="m4_if([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program which can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method == "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi]) +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :) + AC_SUBST([DUMPBIN]) + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +AC_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC*) + # IBM XL 8.0 on PPC + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + hpux9* | hpux10* | hpux11*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl*) + # IBM XL C 8.0/Fortran 10.1 on PPC + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac +AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + ;; + linux* | k*bsd*-gnu) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag= + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + xl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + _LT_TAGVAR(link_all_deplibs, $1)=no + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + AC_LINK_IFELSE(int foo(void) {}, + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + ) + LDFLAGS="$save_LDFLAGS" + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1], + [[If ld is used when linking, flag to hardcode $libdir into a binary + during linking. This must work even if $libdir does not exist]]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting ${shlibpath_var} if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [fix_srcfile_path], [1], + [Fix the shell variable $srcfile for the compiler]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report which library types will actually be built + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC="$lt_save_CC" +])# _LT_LANG_C_CONFIG + + +# _LT_PROG_CXX +# ------------ +# Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++ +# compiler, we have our own version here. +m4_defun([_LT_PROG_CXX], +[ +pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes]) +AC_PROG_CXX +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_CXX + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_CXX], []) + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[AC_REQUIRE([_LT_PROG_CXX])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + LT_PATH_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) + _LT_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd[[12]]*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + gnu*) + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 will use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + xl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=echo + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + + _LT_TAGVAR(GCC, $1)="$GXX" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) +# --------------------------------- +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +]) +dnl Parse the compiler output and extract the necessary +dnl objects, libraries and library flags. +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)="${prev}${p}" + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" + fi + fi + ;; + + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)="$p" + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)="$p" + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling $1 test program" +fi + +$RM -f confest.$objext + +# PORTME: override above test on systems where it is broken +m4_if([$1], [CXX], +[case $host_os in +interix[[3-9]]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + _LT_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_PROG_F77 +# ------------ +# Since AC_PROG_F77 is broken, in that it returns the empty string +# if there is no fortran compiler, we have our own version here. +m4_defun([_LT_PROG_F77], +[ +pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes]) +AC_PROG_F77 +if test -z "$F77" || test "X$F77" = "Xno"; then + _lt_disable_F77=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_F77 + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_F77], []) + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_REQUIRE([_LT_PROG_F77])dnl +AC_LANG_PUSH(Fortran 77) + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_F77" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + CC=${F77-"f77"} + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$G77" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" +fi # test "$_lt_disable_F77" != yes + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_PROG_FC +# ----------- +# Since AC_PROG_FC is broken, in that it returns the empty string +# if there is no fortran compiler, we have our own version here. +m4_defun([_LT_PROG_FC], +[ +pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes]) +AC_PROG_FC +if test -z "$FC" || test "X$FC" = "Xno"; then + _lt_disable_FC=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_FC + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_FC], []) + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_REQUIRE([_LT_PROG_FC])dnl +AC_LANG_PUSH(Fortran) + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_FC" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + CC=${FC-"f95"} + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" +fi # test "$_lt_disable_FC" != yes + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC="$lt_save_CC" +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl +AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +GCC=$lt_save_GCC +AC_LANG_RESTORE +CC="$lt_save_CC" +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ + +m4_defun([AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[AC_MSG_CHECKING([whether the shell understands some XSI constructs]) +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +AC_MSG_RESULT([$xsi_shell]) +_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) + +AC_MSG_CHECKING([whether the shell understands "+="]) +lt_shell_append=no +( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +AC_MSG_RESULT([$lt_shell_append]) +_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PROG_XSI_SHELLFNS +# --------------------- +# Bourne and XSI compatible variants of some useful shell functions. +m4_defun([_LT_PROG_XSI_SHELLFNS], +[case $xsi_shell in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac +} + +# func_basename file +func_basename () +{ + func_basename_result="${1##*/}" +} + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}" +} + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +func_stripname () +{ + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"} +} + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=${1%%=*} + func_opt_split_arg=${1#*=} +} + +# func_lo2o object +func_lo2o () +{ + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=${1%.*}.lo +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=$(( $[*] )) +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=${#1} +} + +_LT_EOF + ;; + *) # Bourne compatible functions. + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + +dnl func_dirname_and_basename +dnl A portable version of this function is already defined in general.m4sh +dnl so there is no need for it here. + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; + esac +} + +# sed scripts: +my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q' +my_sed_long_arg='1s/^-[[^=]]*=//' + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` + func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` +} + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'` +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "$[@]"` +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len` +} + +_LT_EOF +esac + +case $lt_shell_append in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$[1]+=\$[2]" +} +_LT_EOF + ;; + *) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$[1]=\$$[1]\$[2]" +} + +_LT_EOF + ;; + esac +]) diff --git a/common/m4/ltoptions.m4 b/common/m4/ltoptions.m4 new file mode 100644 index 0000000..34151a3 --- /dev/null +++ b/common/m4/ltoptions.m4 @@ -0,0 +1,368 @@ +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltoptions.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) + + +# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) +# ------------------------------------------ +m4_define([_LT_MANGLE_OPTION], +[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) + + +# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) +# --------------------------------------- +# Set option OPTION-NAME for macro MACRO-NAME, and if there is a +# matching handler defined, dispatch to it. Other OPTION-NAMEs are +# saved as a flag. +m4_define([_LT_SET_OPTION], +[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl +m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), + _LT_MANGLE_DEFUN([$1], [$2]), + [m4_warning([Unknown $1 option `$2'])])[]dnl +]) + + +# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) +# ------------------------------------------------------------ +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +m4_define([_LT_IF_OPTION], +[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) + + +# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) +# ------------------------------------------------------- +# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME +# are set. +m4_define([_LT_UNLESS_OPTIONS], +[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), + [m4_define([$0_found])])])[]dnl +m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 +])[]dnl +]) + + +# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) +# ---------------------------------------- +# OPTION-LIST is a space-separated list of Libtool options associated +# with MACRO-NAME. If any OPTION has a matching handler declared with +# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about +# the unknown option and exit. +m4_defun([_LT_SET_OPTIONS], +[# Set options +m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [_LT_SET_OPTION([$1], _LT_Option)]) + +m4_if([$1],[LT_INIT],[ + dnl + dnl Simply set some default values (i.e off) if boolean options were not + dnl specified: + _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no + ]) + _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no + ]) + dnl + dnl If no reference was made to various pairs of opposing options, then + dnl we run the default mode handler for the pair. For example, if neither + dnl `shared' nor `disable-shared' was passed, we enable building of shared + dnl archives by default: + _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) + _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], + [_LT_ENABLE_FAST_INSTALL]) + ]) +])# _LT_SET_OPTIONS + + +## --------------------------------- ## +## Macros to handle LT_INIT options. ## +## --------------------------------- ## + +# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) +# ----------------------------------------- +m4_define([_LT_MANGLE_DEFUN], +[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) + + +# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) +# ----------------------------------------------- +m4_define([LT_OPTION_DEFINE], +[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl +])# LT_OPTION_DEFINE + + +# dlopen +# ------ +LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes +]) + +AU_DEFUN([AC_LIBTOOL_DLOPEN], +[_LT_SET_OPTION([LT_INIT], [dlopen]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `dlopen' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) + + +# win32-dll +# --------- +# Declare package support for building win32 dll's. +LT_OPTION_DEFINE([LT_INIT], [win32-dll], +[enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +esac + +test -z "$AS" && AS=as +_LT_DECL([], [AS], [0], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl +])# win32-dll + +AU_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +_LT_SET_OPTION([LT_INIT], [win32-dll]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `win32-dll' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) + + +# _LT_ENABLE_SHARED([DEFAULT]) +# ---------------------------- +# implement the --enable-shared flag, and supports the `shared' and +# `disable-shared' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_SHARED], +[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) + + _LT_DECL([build_libtool_libs], [enable_shared], [0], + [Whether or not to build shared libraries]) +])# _LT_ENABLE_SHARED + +LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) +]) + +AC_DEFUN([AC_DISABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], [disable-shared]) +]) + +AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_SHARED], []) +dnl AC_DEFUN([AM_DISABLE_SHARED], []) + + + +# _LT_ENABLE_STATIC([DEFAULT]) +# ---------------------------- +# implement the --enable-static flag, and support the `static' and +# `disable-static' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_STATIC], +[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]_LT_ENABLE_STATIC_DEFAULT) + + _LT_DECL([build_old_libs], [enable_static], [0], + [Whether or not to build static libraries]) +])# _LT_ENABLE_STATIC + +LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) +]) + +AC_DEFUN([AC_DISABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], [disable-static]) +]) + +AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_STATIC], []) +dnl AC_DEFUN([AM_DISABLE_STATIC], []) + + + +# _LT_ENABLE_FAST_INSTALL([DEFAULT]) +# ---------------------------------- +# implement the --enable-fast-install flag, and support the `fast-install' +# and `disable-fast-install' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_FAST_INSTALL], +[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([fast-install], + [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) + +_LT_DECL([fast_install], [enable_fast_install], [0], + [Whether or not to optimize for fast installation])dnl +])# _LT_ENABLE_FAST_INSTALL + +LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) + +# Old names: +AU_DEFUN([AC_ENABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `fast-install' option into LT_INIT's first parameter.]) +]) + +AU_DEFUN([AC_DISABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `disable-fast-install' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) +dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) + + +# _LT_WITH_PIC([MODE]) +# -------------------- +# implement the --with-pic flag, and support the `pic-only' and `no-pic' +# LT_INIT options. +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +m4_define([_LT_WITH_PIC], +[AC_ARG_WITH([pic], + [AS_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) + +test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) + +_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl +])# _LT_WITH_PIC + +LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) + +# Old name: +AU_DEFUN([AC_LIBTOOL_PICMODE], +[_LT_SET_OPTION([LT_INIT], [pic-only]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `pic-only' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) + +## ----------------- ## +## LTDL_INIT Options ## +## ----------------- ## + +m4_define([_LTDL_MODE], []) +LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], + [m4_define([_LTDL_MODE], [nonrecursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [recursive], + [m4_define([_LTDL_MODE], [recursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [subproject], + [m4_define([_LTDL_MODE], [subproject])]) + +m4_define([_LTDL_TYPE], []) +LT_OPTION_DEFINE([LTDL_INIT], [installable], + [m4_define([_LTDL_TYPE], [installable])]) +LT_OPTION_DEFINE([LTDL_INIT], [convenience], + [m4_define([_LTDL_TYPE], [convenience])]) diff --git a/common/m4/ltsugar.m4 b/common/m4/ltsugar.m4 new file mode 100644 index 0000000..9000a05 --- /dev/null +++ b/common/m4/ltsugar.m4 @@ -0,0 +1,123 @@ +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltsugar.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) + + +# lt_join(SEP, ARG1, [ARG2...]) +# ----------------------------- +# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their +# associated separator. +# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier +# versions in m4sugar had bugs. +m4_define([lt_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) +m4_define([_lt_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) + + +# lt_car(LIST) +# lt_cdr(LIST) +# ------------ +# Manipulate m4 lists. +# These macros are necessary as long as will still need to support +# Autoconf-2.59 which quotes differently. +m4_define([lt_car], [[$1]]) +m4_define([lt_cdr], +[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], + [$#], 1, [], + [m4_dquote(m4_shift($@))])]) +m4_define([lt_unquote], $1) + + +# lt_append(MACRO-NAME, STRING, [SEPARATOR]) +# ------------------------------------------ +# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. +# Note that neither SEPARATOR nor STRING are expanded; they are appended +# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). +# No SEPARATOR is output if MACRO-NAME was previously undefined (different +# than defined and empty). +# +# This macro is needed until we can rely on Autoconf 2.62, since earlier +# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. +m4_define([lt_append], +[m4_define([$1], + m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) + + + +# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) +# ---------------------------------------------------------- +# Produce a SEP delimited list of all paired combinations of elements of +# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list +# has the form PREFIXmINFIXSUFFIXn. +# Needed until we can rely on m4_combine added in Autoconf 2.62. +m4_define([lt_combine], +[m4_if(m4_eval([$# > 3]), [1], + [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl +[[m4_foreach([_Lt_prefix], [$2], + [m4_foreach([_Lt_suffix], + ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, + [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) + + +# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) +# ----------------------------------------------------------------------- +# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited +# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. +m4_define([lt_if_append_uniq], +[m4_ifdef([$1], + [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], + [lt_append([$1], [$2], [$3])$4], + [$5])], + [lt_append([$1], [$2], [$3])$4])]) + + +# lt_dict_add(DICT, KEY, VALUE) +# ----------------------------- +m4_define([lt_dict_add], +[m4_define([$1($2)], [$3])]) + + +# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) +# -------------------------------------------- +m4_define([lt_dict_add_subkey], +[m4_define([$1($2:$3)], [$4])]) + + +# lt_dict_fetch(DICT, KEY, [SUBKEY]) +# ---------------------------------- +m4_define([lt_dict_fetch], +[m4_ifval([$3], + m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), + m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) + + +# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) +# ----------------------------------------------------------------- +m4_define([lt_if_dict_fetch], +[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], + [$5], + [$6])]) + + +# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) +# -------------------------------------------------------------- +m4_define([lt_dict_filter], +[m4_if([$5], [], [], + [lt_join(m4_quote(m4_default([$4], [[, ]])), + lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), + [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl +]) diff --git a/common/m4/ltversion.m4 b/common/m4/ltversion.m4 new file mode 100644 index 0000000..f3c5309 --- /dev/null +++ b/common/m4/ltversion.m4 @@ -0,0 +1,23 @@ +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# Generated from ltversion.in. + +# serial 3017 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.2.6b]) +m4_define([LT_PACKAGE_REVISION], [1.3017]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.2.6b' +macro_revision='1.3017' +_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) +_LT_DECL(, macro_revision, 0) +]) diff --git a/common/m4/lt~obsolete.m4 b/common/m4/lt~obsolete.m4 new file mode 100644 index 0000000..637bb20 --- /dev/null +++ b/common/m4/lt~obsolete.m4 @@ -0,0 +1,92 @@ +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004. +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 4 lt~obsolete.m4 + +# These exist entirely to fool aclocal when bootstrapping libtool. +# +# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) +# which have later been changed to m4_define as they aren't part of the +# exported API, or moved to Autoconf or Automake where they belong. +# +# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN +# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us +# using a macro with the same name in our local m4/libtool.m4 it'll +# pull the old libtool.m4 in (it doesn't see our shiny new m4_define +# and doesn't know about Autoconf macros at all.) +# +# So we provide this file, which has a silly filename so it's always +# included after everything else. This provides aclocal with the +# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything +# because those macros already exist, or will be overwritten later. +# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. +# +# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. +# Yes, that means every name once taken will need to remain here until +# we give up compatibility with versions before 1.7, at which point +# we need to keep only those names which we still refer to. + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) + +m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) +m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) +m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) +m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) +m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) +m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) +m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) +m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) +m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) +m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) +m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) +m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) +m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) +m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) +m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) +m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) +m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) +m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) +m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) +m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) +m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) +m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) +m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) +m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) +m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) +m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) +m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) +m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) +m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) +m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) +m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) +m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) +m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) +m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) +m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) +m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) +m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])]) +m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) +m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) +m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) +m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) +m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) diff --git a/common/m4/pkg.m4 b/common/m4/pkg.m4 new file mode 100755 index 0000000..3c20213 --- /dev/null +++ b/common/m4/pkg.m4 @@ -0,0 +1,135 @@ +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# +# Copyright © 2004 Scott James Remnant . +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# PKG_PROG_PKG_CONFIG([MIN-VERSION]) +# ---------------------------------- +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_ifval([$1], [$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi + +fi[]dnl +])# PKG_PROG_PKG_CONFIG + +# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# Check to see whether a particular set of modules exists. Similar +# to PKG_CHECK_MODULES(), but does not set variables or print errors. +# +# +# Similar to PKG_CHECK_MODULES, make sure that the first instance of +# this or PKG_CHECK_MODULES is called, or make sure to call +# PKG_CHECK_EXISTS manually +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_ifval([$2], [$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + + +# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +# --------------------------------------------- +m4_define([_PKG_CONFIG], +[if test -n "$PKG_CONFIG"; then + if test -n "$$1"; then + pkg_cv_[]$1="$$1" + else + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], + [pkg_failed=yes]) + fi +else + pkg_failed=untried +fi[]dnl +])# _PKG_CONFIG + +# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# +# +# Note that if there is a possibility the first call to +# PKG_CHECK_MODULES might not happen, you should be sure to include an +# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +# +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +if test $pkg_failed = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" 1>&AS_MESSAGE_LOG_FD + + ifelse([$4], , [AC_MSG_ERROR(dnl +[Package requirements ($2) were not met. +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively you may set the $1_CFLAGS and $1_LIBS environment variables +to avoid the need to call pkg-config. See the pkg-config man page for +more details.])], + [$4]) +elif test $pkg_failed = untried; then + ifelse([$4], , [AC_MSG_FAILURE(dnl +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively you may set the $1_CFLAGS and $1_LIBS environment variables +to avoid the need to call pkg-config. See the pkg-config man page for +more details. + +To get pkg-config, see .])], + [$4]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + ifelse([$3], , :, [$3]) +fi[]dnl +])# PKG_CHECK_MODULES diff --git a/common/m4/progtest.m4 b/common/m4/progtest.m4 new file mode 100755 index 0000000..443c8e3 --- /dev/null +++ b/common/m4/progtest.m4 @@ -0,0 +1,59 @@ +# progtest.m4 serial 2 (gettext-0.10.40) +dnl Copyright (C) 1996-2002 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. +dnl +dnl This file can can be used in projects which are not available under +dnl the GNU General Public License or the GNU Library General Public +dnl License but which still want to provide support for the GNU gettext +dnl functionality. +dnl Please note that the actual code of the GNU gettext library is covered +dnl by the GNU Library General Public License, and the rest of the GNU +dnl gettext package package is covered by the GNU General Public License. +dnl They are *not* in the public domain. + +dnl Authors: +dnl Ulrich Drepper , 1996. + +# Search path for a program which passes the given test. + +dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, +dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) +AC_DEFUN([AM_PATH_PROG_WITH_TEST], +[# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_path_$1, +[case "[$]$1" in + /*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in ifelse([$5], , $PATH, [$5]); do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if [$3]; then + ac_cv_path_$1="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) diff --git a/common/mangle-tmpl.py b/common/mangle-tmpl.py new file mode 100755 index 0000000..d319040 --- /dev/null +++ b/common/mangle-tmpl.py @@ -0,0 +1,155 @@ +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +""" +use the output from gst-xmlinspect.py to mangle tmpl/*.sgml and +insert/overwrite Short Description and Long Description +""" + +# FIXME: right now it uses pygst and scans on its own; +# we really should use inspect/*.xml instead since the result of +# gst-xmlinspect.py is commited by the docs maintainer, who can be +# expected to have pygst, but this step should be done for every docs build, +# so no pygst allowed + +# read in inspect/*.xml +# for every tmpl/element-(name).xml: mangle with details from element + +import glob +import re +import sys +import os + +class Tmpl: + def __init__(self, filename): + self.filename = filename + self._sectionids = [] + self._sections = {} + + def read(self): + """ + Read and parse the sections from the given file. + """ + lines = open(self.filename).readlines() + matcher = re.compile("\n") + id = None + + for line in lines: + match = matcher.search(line) + if match: + id = match.expand("\\1") + self._sectionids.append(id) + self._sections[id] = [] + else: + if not id: + sys.stderr.write( + "WARNING: line before a SECTION header: %s" % line) + else: + self._sections[id].append(line) + + def get_section(self, id): + """ + Get the content from the given section. + """ + return self._sections[id] + + def set_section(self, id, content): + """ + Replace the given section id with the given content. + """ + self._sections[id] = content + + def output(self): + """ + Return the output of the current template in the tmpl/*.sgml format. + """ + lines = [] + for id in self._sectionids: + lines.append("\n" % id) + for line in self._sections[id]: + lines.append(line) + + return "".join(lines) + + def write(self, backup=False): + """ + Write out the template file again, backing up the previous one. + """ + if backup: + target = self.filename + ".mangle.bak" + os.rename(self.filename, target) + + handle = open(self.filename, "w") + handle.write(self.output()) + handle.close() + +from xml.dom.ext.reader import Sax2 +from xml.dom.NodeFilter import NodeFilter + +def get_elements(file): + elements = {} + handle = open(file) + reader = Sax2.Reader() + doc = reader.fromStream(handle) + handle.close() + + walker = doc.createTreeWalker(doc.documentElement, + NodeFilter.SHOW_ELEMENT, None, 0) + while walker.currentNode and walker.currentNode.tagName != 'elements': + walker.nextNode() + + # we're at elements now + el = walker.firstChild() + while walker.currentNode: + element = walker.firstChild() + # loop over children of + name = None + description = None + while walker.currentNode: + if walker.currentNode.tagName == 'name': + name = walker.currentNode.firstChild.data.encode('UTF-8') + if walker.currentNode.tagName == 'description': + description = walker.currentNode.firstChild.data.encode('UTF-8') + if not walker.nextSibling(): break + # back up to + walker.parentNode() + elements[name] = {'description': description} + + if not walker.nextSibling(): break + + return elements + + +def main(): + if not len(sys.argv) == 3: + sys.stderr.write('Please specify the inspect/ dir and the tmpl/ dir') + sys.exit(1) + + inspectdir = sys.argv[1] + tmpldir = sys.argv[2] + + # parse all .xml files; build map of element name -> short desc + #for file in glob.glob("inspect/plugin-*.xml"): + elements = {} + for file in glob.glob("%s/plugin-*.xml" % inspectdir): + elements.update(get_elements(file)) + + for file in glob.glob("%s/element-*.sgml" % tmpldir): + base = os.path.basename(file) + element = base[len("element-"):-len(".sgml")] + tmpl = Tmpl(file) + tmpl.read() + if element in elements.keys(): + description = elements[element]['description'] + tmpl.set_section("Short_Description", "%s\n\n" % description) + + # put in an include if not yet there + line = '\n' + section = tmpl.get_section("Long_Description") + if not section[0] == line: + section.insert(0, line) + tmpl.set_section("Long_Description", section) + tmpl.write() + +main() diff --git a/common/plugins.xsl b/common/plugins.xsl new file mode 100755 index 0000000..150087f --- /dev/null +++ b/common/plugins.xsl @@ -0,0 +1,200 @@ + + + + + + + + + + + + -plugins- + + + + + + + + + + + + + Element Information + + + + + plugin + + + + plugin- + + + + + + + + author + + + + + + + class + + + + + + + + Element Pads + + + + + name + + + + + + + direction + + + + + + + presence + + + + + + + details + + + + + + + + + + + + + + + + + + -plugins-plugin- + + + + + + 3 + FIXME Library + + + + + + plugin- + + + + + + + + + + + Plugin Information + + + + filename + + + + + + + version + + + + + + + run-time license + + + + + + + package + + + + + + + origin + + + + + + + + + + + + + + + + + + + + + + + Elements + + + + + + + + + + + + + + diff --git a/common/po.mak b/common/po.mak new file mode 100755 index 0000000..e019fac --- /dev/null +++ b/common/po.mak @@ -0,0 +1,4 @@ +# rule to download the latest .po files +download-po: $(top_srcdir)/common/download-translations + $(top_srcdir)/common/download-translations $(PACKAGE) + diff --git a/common/release.mak b/common/release.mak new file mode 100755 index 0000000..afb0c8c --- /dev/null +++ b/common/release.mak @@ -0,0 +1,25 @@ +# include this snippet to add a common release: target by using +# include $(top_srcdir)/common/release.mak + +# make bz2 as well +AUTOMAKE_OPTIONS = dist-bzip2 + +release: dist + $(MAKE) $(PACKAGE)-$(VERSION).tar.gz.md5 + $(MAKE) $(PACKAGE)-$(VERSION).tar.bz2.md5 + +# generate md5 sum files +%.md5: % + md5sum $< > $@ + +# check that no marshal or enumtypes files are included +# this in turn ensures that distcheck fails for missing .list files which is currently +# shadowed when the corresponding .c and .h files are included. +distcheck-hook: + @test "x" = "x`find $(distdir) -name \*-enumtypes.[ch] | grep -v win32`" && \ + test "x" = "x`find $(distdir) -name \*-marshal.[ch]`" || \ + ( $(ECHO) "*** Leftover enumtypes or marshal files in the tarball." && \ + $(ECHO) "*** Make sure the following files are not disted:" && \ + find $(distdir) -name \*-enumtypes.[ch] | grep -v win32 && \ + find $(distdir) -name \*-marshal.[ch] && \ + false ) diff --git a/common/scangobj-merge.py b/common/scangobj-merge.py new file mode 100755 index 0000000..4917255 --- /dev/null +++ b/common/scangobj-merge.py @@ -0,0 +1,226 @@ +#!/usr/bin/python +# -*- Mode: Python -*- +# vi:si:et:sw=4:sts=4:ts=4 + +""" +parse, update and write .signals and .args files +""" + +from twisted.python import util + +import sys +import os + +def debug(*args): + pass + +class Object: + def __init__(self, name): + self._signals = util.OrderedDict() + self._args = util.OrderedDict() + self.name = name + + def __repr__(self): + return "" % self.name + + def add_signal(self, signal, overwrite=True): + if not overwrite and self._signals.has_key(signal.name): + raise IndexError, "signal %s already in %r" % (signal.name, self) + self._signals[signal.name] = signal + + def add_arg(self, arg, overwrite=True): + if not overwrite and self._args.has_key(arg.name): + raise IndexError, "arg %s already in %r" % (arg.name, self) + self._args[arg.name] = arg + +class Docable: + def __init__(self, **kwargs): + for key in self.attrs: + setattr(self, key, kwargs[key]) + self.dict = kwargs + + def __repr__(self): + return "<%r %s>" % (str(self.__class__), self.name) + +class Signal(Docable): + attrs = ['name', 'returns', 'args'] + +class Arg(Docable): + attrs = ['name', 'type', 'range', 'flags', 'nick', 'blurb', 'default'] + +class GDoc: + def load_file(self, filename): + try: + lines = open(filename).readlines() + self.load_data("".join(lines)) + except IOError: + print "WARNING - could not read from %s" % filename + + def save_file(self, filename, backup=False): + """ + Save the signals information to the given .signals file if the + file content changed. + """ + olddata = None + try: + lines = open(filename).readlines() + olddata = "".join(lines) + except IOError: + print "WARNING - could not read from %s" % filename + newdata = self.get_data() + if olddata and olddata == newdata: + return + + if olddata: + if backup: + os.rename(filename, filename + '.bak') + + handle = open(filename, "w") + handle.write(newdata) + handle.close() + +class Signals(GDoc): + def __init__(self): + self._objects = util.OrderedDict() + + def load_data(self, data): + """ + Load the .signals lines, creating our list of objects and signals. + """ + import re + smatcher = re.compile( + '(?s)' # make . match \n + '\n(.*?)\n' + ) + nmatcher = re.compile( + '' + '(?P\S*)' # store object + '::' + '(?P\S*)' # store signal + '' + ) + rmatcher = re.compile( + '(?s)' # make . match \n + '(?P\S*)\n' # store returns + '(?P.*)' # store args + ) + for block in smatcher.findall(data): + nmatch = nmatcher.search(block) + if nmatch: + o = nmatch.group('object') + debug("Found object", o) + debug("Found signal", nmatch.group('signal')) + if not self._objects.has_key(o): + object = Object(o) + self._objects[o] = object + + rmatch = rmatcher.search(block) + if rmatch: + dict = rmatch.groupdict().copy() + dict['name'] = nmatch.group('signal') + signal = Signal(**dict) + self._objects[o].add_signal(signal) + + def get_data(self): + lines = [] + for o in self._objects.values(): + for s in o._signals.values(): + block = """ +%(object)s::%(name)s +%(returns)s +%(args)s +""" + d = s.dict.copy() + d['object'] = o.name + lines.append(block % d) + + return "\n".join(lines) + '\n' + +class Args(GDoc): + def __init__(self): + self._objects = util.OrderedDict() + + def load_data(self, data): + """ + Load the .args lines, creating our list of objects and args. + """ + import re + amatcher = re.compile( + '(?s)' # make . match \n + '\n(.*?)\n' + ) + nmatcher = re.compile( + '' + '(?P\S*)' # store object + '::' + '(?P\S*)' # store arg + '' + ) + rmatcher = re.compile( + '(?s)' # make . match \n + '(?P\S*)\n' # store type + '(?P.*?)\n' # store range + '(?P\S*)\n' # store flags + '(?P.*?)\n' # store nick + '(?P.*?)\n' # store blurb + '(?P.*?)\n' # store default + ) + for block in amatcher.findall(data): + nmatch = nmatcher.search(block) + if nmatch: + o = nmatch.group('object') + debug("Found object", o) + debug("Found arg", nmatch.group('arg')) + if not self._objects.has_key(o): + object = Object(o) + self._objects[o] = object + + rmatch = rmatcher.search(block) + if rmatch: + dict = rmatch.groupdict().copy() + dict['name'] = nmatch.group('arg') + arg = Arg(**dict) + self._objects[o].add_arg(arg) + else: + print "ERROR: could not match arg from block %s" % block + + def get_data(self): + lines = [] + for o in self._objects.values(): + for a in o._args.values(): + block = """ +%(object)s::%(name)s +%(type)s +%(range)s +%(flags)s +%(nick)s +%(blurb)s +%(default)s + +""" + d = a.dict.copy() + d['object'] = o.name + lines.append(block % d) + + return "\n".join(lines) + '\n' + +def main(argv): + modulename = None + try: + modulename = argv[1] + except IndexError: + sys.stderr.write('Pleae provide a documentation module name\n') + sys.exit(1) + + print "Merging scangobj output for %s" % modulename + signals = Signals() + signals.load_file(modulename + '.signals') + signals.load_file(modulename + '.signals.new') + signals.save_file(modulename + '.signals', backup=True) + + args = Args() + args.load_file(modulename + '.args') + args.load_file(modulename + '.args.new') + args.save_file(modulename + '.args', backup=True) + +main(sys.argv) diff --git a/common/upload.mak b/common/upload.mak new file mode 100755 index 0000000..60731e5 --- /dev/null +++ b/common/upload.mak @@ -0,0 +1,33 @@ +# this snippet is to be included by both our docbook manuals +# and gtk-doc API references + +# it adds an upload target to each of these dir's Makefiles + +# each Makefile.am should define the following variables: +# - DOC: the base name of the documentation +# (faq, manual, pwg, gstreamer, gstreamer-libs) +# - FORMATS: the formats in which DOC is output +# (html ps pdf) + +# if you want to use it, make sure your $HOME/.ssh/config file contains the +# correct User entry for the Host entry for the DOC_SERVER + +# these variables define the location of the online docs +DOC_SERVER = gstreamer.freedesktop.org +DOC_BASE = /srv/gstreamer.freedesktop.org/www/data/doc +DOC_URL = $(DOC_SERVER):$(DOC_BASE) + +upload: $(FORMATS) + @if test "x$(PACKAGE_VERSION_NANO)" = x0; then \ + export DOCVERSION=$(VERSION); \ + else export DOCVERSION=head; \ + fi; \ + export DIR=$(DOC_BASE)/gstreamer/$$DOCVERSION/$(DOC); \ + ssh $(DOC_SERVER) mkdir -p $$DIR; \ + if echo $(FORMATS) | grep html > /dev/null; then export SRC="$$SRC html"; fi; \ + if echo $(FORMATS) | grep ps > /dev/null; then export SRC="$$SRC $(DOC).ps"; fi; \ + if echo $(FORMATS) | grep pdf > /dev/null; then export SRC="$$SRC $(DOC).pdf"; fi; \ + echo Uploading $$SRC to $(DOC_SERVER):$$DIR; \ + rsync -rv -e ssh --delete $$SRC $(DOC_SERVER):$$DIR; \ + ssh $(DOC_SERVER) chmod -R g+w $$DIR; \ + echo Done diff --git a/common/win32.mak b/common/win32.mak new file mode 100755 index 0000000..63b1310 --- /dev/null +++ b/common/win32.mak @@ -0,0 +1,54 @@ +# various tests to make sure we dist the win32 stuff (for MSVC builds) right + +# the MANIFEST contains all win32 related files that should be disted +win32 = $(shell cat $(top_srcdir)/win32/MANIFEST) + +# wildcard is apparently not portable to other makes, hence the use of find +# these are library .def files with the symbols to export +win32defs = $(shell find $(top_srcdir)/win32/common -name '*.def') + +# wildcard is apparently not portable to other makes, hence the use of find +# these are files that need to be disted with CRLF line endings: +win32crlf = $(shell find $(top_srcdir)/win32 -name '*.dsw' -o -name '*.dsp') + +win32-debug: + @echo; \ + echo win32 = $(win32); \ + echo; \ + echo win32defs = $(win32defs); \ + echo; \ + echo win32crlf = $(win32crlf); \ + echo + +win32-check-crlf: + @echo Checking win32 files for CR LF line endings ...; \ + fail=0 ; \ + for each in $(win32crlf) ; do \ + if ! (file $$each | grep CRLF >/dev/null) ; then \ + echo $$each must be fixed to have CRLF line endings ; \ + fail=1; \ + fi ; \ + done ; \ + exit $$fail + +# make sure all symbols we export on linux are defined in the win32 .def too +# (don't care about other unixes for now, it's enough if it works on one of +# the linux build bots; we assume .so ) +check-exports: + fail=0 ; \ + for l in $(win32defs); do \ + libbase=`basename "$$l" ".def"`; \ + libso=`find "$(top_builddir)" -name "$$libbase-@GST_MAJORMINOR@.so"`; \ + libdef="$(top_srcdir)/win32/common/$$libbase.def"; \ + if test "x$$libso" != "x"; then \ + echo Checking symbols in $$libso; \ + if ! ($(top_srcdir)/common/check-exports $$libdef $$libso) ; then \ + fail=1; \ + fi; \ + fi; \ + done + + +dist-hook: check-exports win32-check-crlf + + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..488d9b9 --- /dev/null +++ b/configure.ac @@ -0,0 +1,460 @@ + +AC_INIT(extension, 1.0) + +dnl versions of gstreamer and plugins-base +GST_MAJORMINOR=1.0 +GST_REQUIRED=1.2.0 +GSTPB_REQUIRED=1.2.0 +EFL_REQUIRED=1.0.0 + +dnl fill in your package name and version here +dnl the fourth (nano) number should be 0 for a release, 1 for CVS, +dnl and 2... for a prerelease + +dnl when going to/from release please set the nano correctly ! +dnl releases only do Wall, cvs and prerelease does Werror too +AS_VERSION(gst-plugin, GST_PLUGIN_VERSION, 0, 10, 0, 1, + GST_PLUGIN_CVS="no", GST_PLUGIN_CVS="yes") + +dnl AM_MAINTAINER_MODE provides the option to enable maintainer mode +AM_MAINTAINER_MODE + +#AM_INIT_AUTOMAKE($PACKAGE, $VERSION) +AM_INIT_AUTOMAKE + +#AC_CONFIG_MACRO_DIR([m4]) + +dnl make aclocal work in maintainer mode +dnl AC_SUBST(ACLOCAL_AMFLAGS, "-I m4") + +dnl Add parameters for aclocal +AC_SUBST(ACLOCAL_AMFLAGS, "-I m4 -I common/m4") + +AM_CONFIG_HEADER(config.h) + +dnl check for tools +AC_PROG_CC +AC_PROG_CXX +AC_PROG_LIBTOOL + +dnl decide on error flags +AS_COMPILER_FLAG(-Wall, GST_WALL="yes", GST_WALL="no") + +if test "x$GST_WALL" = "xyes"; then + GST_ERROR="$GST_ERROR -Wall" + +# if test "x$GST_PLUGIN_CVS" = "xyes"; then +# AS_COMPILER_FLAG(-Werror,GST_ERROR="$GST_ERROR -Werror",GST_ERROR="$GST_ERROR") +# fi +fi + +dnl Check for pkgconfig first +AC_CHECK_PROG(HAVE_PKGCONFIG, pkg-config, yes, no) + +dnl Give error and exit if we don't have pkgconfig +if test "x$HAVE_PKGCONFIG" = "xno"; then + AC_MSG_ERROR(you need to have pkgconfig installed !) +fi + +dnl Now we're ready to ask for gstreamer libs and cflags +dnl And we can also ask for the right version of gstreamer +AM_CONDITIONAL([IS_VODA_SDK], [test "x$DISTRO" = "xvodafone-sdk"]) +AM_CONDITIONAL([ISPROTECTOR_VODA_SDK], [test "x$DISTRO" = "xvodafone-sdk" && test "x$MACHINE" = "xprotector"]) +AM_CONDITIONAL([ISVOLANS_VODA_SDK], [test "x$DISTRO" = "xvodafone-sdk" && test "x$MACHINE" = "xvolans"]) +AM_CONDITIONAL([ISPROTECTOR_TARGET], [test "x$ARCH" = "xarm" && test "x$MACHINE" = "xprotector"]) +AM_CONDITIONAL([ISVOLANS_TARGET], [test "x$ARCH" = "xarm" && test "x$MACHINE" = "xvolans"]) + +PKG_CHECK_MODULES(GST, \ + gstreamer-$GST_MAJORMINOR >= $GST_REQUIRED, + HAVE_GST=yes,HAVE_GST=no) + +dnl Give error and exit if we don't have gstreamer +if test "x$HAVE_GST" = "xno"; then + AC_MSG_ERROR(you need gstreamer development packages installed !) +fi + +dnl append GST_ERROR cflags to GST_CFLAGS +GST_CFLAGS="$GST_CFLAGS $GST_ERROR" + +dnl make GST_CFLAGS and GST_LIBS available +PKG_CHECK_MODULES(GST, gstreamer-1.0 >= 1.2.0) +AC_SUBST(GST_CFLAGS) +AC_SUBST(GST_LIBS) + +dnl make GST_MAJORMINOR available in Makefile.am +AC_SUBST(GST_MAJORMINOR) + +dnl If we need them, we can also use the base class libraries +PKG_CHECK_MODULES(GST_BASE, gstreamer-base-$GST_MAJORMINOR >= $GST_REQUIRED, + HAVE_GST_BASE=yes, HAVE_GST_BASE=no) + +dnl Give a warning if we don't have gstreamer libs +dnl you can turn this into an error if you need them +if test "x$HAVE_GST_BASE" = "xno"; then + AC_MSG_NOTICE(no GStreamer base class libraries found (gstreamer-base-$GST_MAJORMINOR)) +fi + +dnl make _CFLAGS and _LIBS available +AC_SUBST(GST_BASE_CFLAGS) +AC_SUBST(GST_BASE_LIBS) + +dnl If we need them, we can also use the gstreamer-plugins-base libraries +PKG_CHECK_MODULES(GSTPB_BASE, + gstreamer-plugins-base-$GST_MAJORMINOR >= $GSTPB_REQUIRED, + HAVE_GSTPB_BASE=yes, HAVE_GSTPB_BASE=no) + +dnl Give a warning if we don't have gstreamer libs +dnl you can turn this into an error if you need them +if test "x$HAVE_GSTPB_BASE" = "xno"; then + AC_MSG_NOTICE(no GStreamer Plugins Base libraries found (gstreamer-plugins-base-$GST_MAJORMINOR)) +fi + +dnl make _CFLAGS and _LIBS available +AC_SUBST(GSTPB_BASE_CFLAGS) +AC_SUBST(GSTPB_BASE_LIBS) + +dnl If we need them, we can also use the gstreamer-controller libraries +PKG_CHECK_MODULES(GSTCTRL, + gstreamer-controller-$GST_MAJORMINOR >= $GSTPB_REQUIRED, + HAVE_GSTCTRL=yes, HAVE_GSTCTRL=no) + +dnl Give a warning if we don't have gstreamer-controller +dnl you can turn this into an error if you need them +if test "x$HAVE_GSTCTRL" = "xno"; then + AC_MSG_NOTICE(no GStreamer Controller libraries found (gstreamer-controller-$GST_MAJORMINOR)) +fi + +dnl make _CFLAGS and _LIBS available +AC_SUBST(GSTCTRL_CFLAGS) +AC_SUBST(GSTCTRL_LIBS) + +dnl set the plugindir where plugins should be installed +if test "x${prefix}" = "x$HOME"; then + plugindir="$HOME/.gstreamer-$GST_MAJORMINOR/plugins" +else + plugindir="\$(libdir)/gstreamer-$GST_MAJORMINOR" +fi +AC_SUBST(plugindir) + +dnl set proper LDFLAGS for plugins +#GST_PLUGIN_LDFLAGS='-module -avoid-version -export-symbols-regex [_]*\(gst_\|Gst\|GST_\).*' +GST_PLUGIN_LDFLAGS='-module -avoid-version -export-symbols-regex [_]*\(gst_\|Gst\|GST_\|FIR_\|arkamys_malloc\|arkamys_free\).*' +#GST_PLUGIN_LDFLAGS='-module -avoid-version' +AC_SUBST(GST_PLUGIN_LDFLAGS) + + +PKG_CHECK_MODULES(GST_AUDIO, gstreamer-audio-$GST_MAJORMINOR >= $GST_REQUIRED ) + + +dnl make _CFLAGS and _LIBS available +AC_SUBST(GST_AUDIO_CFLAGS) +AC_SUBST(GST_AUDIO_LIBS) + +PKG_CHECK_MODULES(GST_VIDEO, gstreamer-video-$GST_MAJORMINOR >= $GST_REQUIRED) + +dnl make _CFLAGS and _LIBS available +AC_SUBST(GST_VIDEO_CFLAGS) +AC_SUBST(GST_VIDEO_LIBS) + +dnl xvimagesrc _CFLAGS and _LIB available + +PKG_CHECK_MODULES(DRI2, libdri2) +AC_SUBST(DRI2_CFLAGS) +AC_SUBST(DRI2_LIBS) + +PKG_CHECK_MODULES(X11, x11) +AC_SUBST(X11_CFLAGS) +AC_SUBST(X11_LIBS) + +PKG_CHECK_MODULES(XEXT, xext) +AC_SUBST(XEXT_CFLAGS) +AC_SUBST(XEXT_LIBS) + +PKG_CHECK_MODULES(XV, xv) +AC_SUBST(XV_CFLAGS) +AC_SUBST(XV_LIBS) + +PKG_CHECK_MODULES(XDAMAGE, xdamage) +AC_SUBST(XDAMAGE_CFLAGS) +AC_SUBST(XDAMAGE_LIBS) + +PKG_CHECK_MODULES(DRM, libdrm) +AC_SUBST(DRM_CFLAGS) +AC_SUBST(DRM_LIBS) + +PKG_CHECK_MODULES(DRM, libdrm-devel) +AC_SUBST(DRM_DEVEL_CFLAGS) +AC_SUBST(DRM_DEVEL_LIBS) + +PKG_CHECK_MODULES(TBM, libtbm) +AC_SUBST(TBM_CFLAGS) +AC_SUBST(TBM_LIBS) + +dnl required package for evasimagesink/evaspixmapsink +PKG_CHECK_MODULES(EFL, [ + evas >= $EFL_REQUIRED + ecore >= $EFL_REQUIRED + ecore-x >= $EFL_REQUIRED +], [ + AC_SUBST(EFL_CFLAGS) + AC_SUBST(EFL_LIBS) +], [ + AC_MSG_ERROR([ + You need to install or upgrade the EFL development + packages on your system. On debian-based systems these are + libevas-dev and libecore-dev. + The minimum version required is $EFL_REQUIRED. + ]) +]) + +dnl *** belows are related to evaspixmapsink plug-ins *** +AG_GST_ARG_WITH_PACKAGE_NAME +AG_GST_ARG_WITH_PACKAGE_ORIGIN + +dnl set license and copyright notice +GST_LICENSE="LGPL" +AC_DEFINE_UNQUOTED(GST_LICENSE, "$GST_LICENSE", [GStreamer license]) +AC_SUBST(GST_LICENSE) + +echo +AC_MSG_NOTICE([Checking libraries for evaspixmapsink plugin]) +echo +dnl *** X11 *** +translit(dnm, m, l) AM_CONDITIONAL(USE_X, true) +AG_GST_CHECK_FEATURE(X, [X libraries and plugins], + [evaspixmapsink], [ + AC_PATH_XTRA + ac_cflags_save="$CFLAGS" + ac_cppflags_save="$CPPFLAGS" + CFLAGS="$CFLAGS $X_CFLAGS" + CPPFLAGS="$CPPFLAGS $X_CFLAGS" + + dnl now try to find the HEADER + AC_CHECK_HEADER(X11/Xlib.h, HAVE_X="yes", HAVE_X="no") + + if test "x$HAVE_X" = "xno" + then + AC_MSG_NOTICE([cannot find X11 development files]) + else + dnl this is much more than we want + X_LIBS="$X_LIBS $X_PRE_LIBS $X_EXTRA_LIBS" + dnl AC_PATH_XTRA only defines the path needed to find the X libs, + dnl it does not add the libs; therefore we add them here + X_LIBS="$X_LIBS -lX11" + AC_SUBST(X_CFLAGS) + AC_SUBST(X_LIBS) + fi + AC_SUBST(HAVE_X) + CFLAGS="$ac_cflags_save" + CPPFLAGS="$ac_cppflags_save" +]) + +dnl Check for Xv extension +translit(dnm, m, l) AM_CONDITIONAL(USE_XVIDEO, true) +AG_GST_CHECK_FEATURE(XVIDEO, [X11 XVideo extensions], + [evaspixmapsink], [ +AG_GST_CHECK_XV +]) + +dnl check for X Shm +translit(dnm, m, l) AM_CONDITIONAL(USE_XSHM, true) +AG_GST_CHECK_FEATURE(XSHM, [X Shared Memory extension], , [ + if test x$HAVE_X = xyes; then + AC_CHECK_LIB(Xext, XShmAttach, + HAVE_XSHM="yes", HAVE_XSHM="no", + $X_LIBS) + if test "x$HAVE_XSHM" = "xyes"; then + XSHM_LIBS="-lXext" + else + dnl On AIX, it is in XextSam instead, but we still need -lXext + AC_CHECK_LIB(XextSam, XShmAttach, + HAVE_XSHM="yes", HAVE_XSHM="no", + $X_LIBS) + if test "x$HAVE_XSHM" = "xyes"; then + XSHM_LIBS="-lXext -lXextSam" + fi + fi + fi +], , [ + AC_SUBST(HAVE_XSHM) + AC_SUBST(XSHM_LIBS) +]) + +dnl PKG_CHECK_MODULES(UDEVMGR, unified-dev-mgr) +dnl AC_SUBST(UDEVMGR_CFLAGS) +dnl AC_SUBST(UDEVMGR_LIBS) + +dnl use ext-encodebin -------------------------------------------------------------------------- +AC_ARG_ENABLE(ext-encodebin, AC_HELP_STRING([--enable-ext-encodebin], [using encodebin]), + [ + case "${enableval}" in + yes) GST_EXT_USE_EXT_ENCODEBIN=yes ;; + no) GST_EXT_USE_EXT_ENCODEBIN=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ext-encodebin) ;; + esac + ], + [GST_EXT_USE_EXT_ENCODEBIN=yes]) +AM_CONDITIONAL(GST_EXT_USE_EXT_ENCODEBIN, test "x$GST_EXT_USE_EXT_ENCODEBIN" = "xyes") + +dnl use ext-evasimagesink -------------------------------------------------------------------------- +AC_ARG_ENABLE(ext-evasimagesink, AC_HELP_STRING([--enable-ext-evasimagesink], [using evasimagesink]), + [ + case "${enableval}" in + yes) GST_EXT_USE_EXT_EVASIMAGESINK=yes ;; + no) GST_EXT_USE_EXT_EVASIMAGESINK=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ext-evasimagesink) ;; + esac + ], + [GST_EXT_USE_EXT_EVASIMAGESINK=yes]) +AM_CONDITIONAL(GST_EXT_USE_EXT_EVASIMAGESINK, test "x$GST_EXT_USE_EXT_EVASIMAGESINK" = "xyes") + +dnl use evaspixmapsink --------------------------------------------------------------------------- +AC_ARG_ENABLE(ext-evaspixmapsink, AC_HELP_STRING([--enable-ext-evaspixmapsink], [using evaspixmapsink]), + [ + case "${enableval}" in + yes) GST_EXT_USE_EXT_EVASPIXMAPSINK=yes ;; + no) GST_EXT_USE_EXT_EVASPIXMAPSINK=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ext-evaspixmapsink) ;; + esac + ], + [GST_EXT_USE_EXT_EVASPIXMAPSINK=yes]) +AM_CONDITIONAL(GST_EXT_USE_EXT_EVASPIXMAPSINK, test "x$GST_EXT_USE_EXT_EVASPIXMAPSINK" = "xyes") + +dnl use ext-xvimagesrc-------------------------------------------------------------------------- +AC_ARG_ENABLE(ext-xvimagesrc, AC_HELP_STRING([--enable-ext-xvimagesrc], [using xvimagesrc]), + [ + case "${enableval}" in + yes) GST_EXT_USE_EXT_XVIMAGESRC=yes ;; + no) GST_EXT_USE_EXT_XVIMAGESRC=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ext-xvimagesrc) ;; + esac + ], + [GST_EXT_USE_EXT_XVIMAGESRC=yes]) +AM_CONDITIONAL(GST_EXT_USE_EXT_XVIMAGESRC, test "x$GST_EXT_USE_EXT_XVIMAGESRC" = "xyes") + +dnl use ext-drmsrc -------------------------------------------------------------------------- +AC_ARG_ENABLE(ext-drmsrc, AC_HELP_STRING([--enable-ext-drmsrc], [using drmsrc]), + [ + case "${enableval}" in + yes) GST_EXT_USE_EXT_DRMSRC=yes ;; + no) GST_EXT_USE_EXT_DRMSRC=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ext-drmsrc) ;; + esac + ], + [GST_EXT_USE_EXT_DRMSRC=yes]) +AM_CONDITIONAL(GST_EXT_USE_EXT_DRMSRC, test "x$GST_EXT_USE_EXT_DRMSRC" = "xyes") +dnl use ext-toggle -------------------------------------------------------------------------- +AC_ARG_ENABLE(ext-toggle, AC_HELP_STRING([--enable-ext-toggle], [using toggle]), + [ + case "${enableval}" in + yes) GST_EXT_USE_EXT_TOGGLE=yes ;; + no) GST_EXT_USE_EXT_TOGGLE=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ext-toggle) ;; + esac + ], + [GST_EXT_USE_EXT_TOGGLE=yes]) +AM_CONDITIONAL(GST_EXT_USE_EXT_TOGGLE, test "x$GST_EXT_USE_EXT_TOGGLE" = "xyes") + +dnl for i386 -------------------------------------------------------------------------- +AC_ARG_ENABLE(i386, AC_HELP_STRING([--enable-i386], [i386 build]), + [ + case "${enableval}" in + yes) IS_I386=yes ;; + no) IS_I386=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-i386) ;; + esac + ], + [IS_I386=no]) +AM_CONDITIONAL([IS_I386], [test "x$IS_I386" = "xyes"]) + +dnl use ext-pdpushsrc -------------------------------------------------------------------------- +AC_ARG_ENABLE(ext-pdpushsrc, AC_HELP_STRING([--enable-ext-pdpushsrc], [using pdpushsrc]), +[ + case "${enableval}" in + yes) GST_EXT_USE_EXT_PD_PUSHSRC=yes ;; + no) GST_EXT_USE_EXT_PD_PUSHSRC=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ext-pdpushsrc) ;; + esac + ], + [GST_EXT_USE_EXT_PD_PUSHSRC=yes]) +AM_CONDITIONAL(GST_EXT_USE_EXT_PD_PUSHSRC, test "x$GST_EXT_USE_EXT_PD_PUSHSRC" = "xyes") +dnl use ext-audiotp -------------------------------------------------------------------------- +AC_ARG_ENABLE(ext-audiotp, AC_HELP_STRING([--enable-ext-audiotp], [using audiotp]), +[ + case "${enableval}" in + yes) GST_EXT_USE_EXT_AUDIOTP=yes ;; + no) GST_EXT_USE_EXT_AUDIOTP=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ext-audiotp) ;; + esac + ], + [GST_EXT_USE_EXT_AUDIOTP=yes]) +AM_CONDITIONAL(GST_EXT_USE_EXT_AUDIOTP, test "x$GST_EXT_USE_EXT_AUDIOTP" = "xyes") + +dnl use ext-audioeq -------------------------------------------------------------------------- +AC_ARG_ENABLE(ext-audioeq, AC_HELP_STRING([--enable-ext-audioeq], [using audioeq]), +[ + case "${enableval}" in + yes) GST_EXT_USE_EXT_AUDIOEQ=yes ;; + no) GST_EXT_USE_EXT_AUDIOEQ=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ext-audioeq) ;; + esac + ], + [GST_EXT_USE_EXT_AUDIOEQ=yes]) +AM_CONDITIONAL(GST_EXT_USE_EXT_AUDIOEQ, test "x$GST_EXT_USE_EXT_AUDIOEQ" = "xyes") + +dnl use ext-fimcconvert ---------------------------------------------------------------------- +AC_ARG_ENABLE(ext-fimcconvert, AC_HELP_STRING([--enable-ext-fimcconvert], [using fimcconvert]), +[ + case "${enableval}" in + yes) GST_EXT_USE_EXT_FIMCCONVERT=yes ;; + no) GST_EXT_USE_EXT_FIMCCONVERT=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ext-fimcconvert) ;; + esac + ], + [GST_EXT_USE_EXT_FIMCCONVERT=yes]) +AM_CONDITIONAL(GST_EXT_USE_EXT_FIMCCONVERT, test "x$GST_EXT_USE_EXT_FIMCCONVERT" = "xyes") + +dnl use ext-wfdrtspsrc -------------------------------------------------------------------------- +AC_ARG_ENABLE(ext-wfdrtspsrc, AC_HELP_STRING([--enable-ext-wfdrtspsrc], [using wfdrtspsrc]), +[ + case "${enableval}" in + yes) GST_EXT_USE_EXT_WFDRTSPSRC=yes ;; + no) GST_EXT_USE_EXT_WFDRTSPSRC=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-ext-wfdrtspsrc) ;; + esac + ], + [GST_EXT_USE_EXT_WFDRTSPSRC=yes]) +AM_CONDITIONAL(GST_EXT_USE_EXT_WFDRTSPSRC, test "x$GST_EXT_USE_EXT_WFDRTSPSRC" = "xyes") +dnl if [test "x$GST_EXT_USE_EXT_WFDRTSPSRC" = "xyes"]; +dnl then +dnl PKG_CHECK_MODULES(MM_WFD_COMMON, mm-scmirroring-common) +dnl AC_SUBST(MM_WFD_COMMON_CFLAGS) +dnl AC_SUBST(MM_WFD_COMMON_LIBS) +dnl fi + +AC_OUTPUT( +Makefile +common/Makefile +common/m4/Makefile +pdpushsrc/Makefile +pdpushsrc/src/Makefile +encodebin/Makefile +encodebin/src/Makefile +evasimagesink/Makefile +evasimagesink/src/Makefile +evaspixmapsink/Makefile +xvimagesrc/Makefile +xvimagesrc/src/Makefile +toggle/Makefile +toggle/src/Makefile +drmsrc/Makefile +drmsrc/src/Makefile +audiotp/Makefile +audiotp/src/Makefile +audioeq/Makefile +audioeq/src/Makefile +fimcconvert/Makefile +fimcconvert/src/Makefile +dnl wfdrtspsrc/Makefile +dnl wfdrtspsrc/src/Makefile +) diff --git a/drmsrc/Makefile.am b/drmsrc/Makefile.am new file mode 100755 index 0000000..308a09c --- /dev/null +++ b/drmsrc/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/drmsrc/src/Makefile.am b/drmsrc/src/Makefile.am new file mode 100755 index 0000000..842ed43 --- /dev/null +++ b/drmsrc/src/Makefile.am @@ -0,0 +1,27 @@ +# plugindir is set in configure + +############################################################################## +# change libgstplugin.la to something more suitable, e.g. libmysomething.la # +############################################################################## +plugin_LTLIBRARIES = libgstdrmsrc.la + +############################################################################## +# for the next set of variables, rename the prefix if you renamed the .la, # +# e.g. libgstplugin_la_SOURCES => libmysomething_la_SOURCES # +# libgstplugin_la_CFLAGS => libmysomething_la_CFLAGS # +# libgstplugin_la_LIBADD => libmysomething_la_LIBADD # +# libgstplugin_la_LDFLAGS => libmysomething_la_LDFLAGS # +############################################################################## + +# sources used to compile this plug-in +libgstdrmsrc_la_SOURCES = gstdrmsrc.c + +# flags used to compile this plugin +# add other _CFLAGS and _LIBS as needed +libgstdrmsrc_la_CFLAGS = $(GST_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 +libgstdrmsrc_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) +libgstdrmsrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +# headers we need but don't want installed +noinst_HEADERS = gstdrmsrc.h + diff --git a/drmsrc/src/gstdrmsrc.c b/drmsrc/src/gstdrmsrc.c new file mode 100755 index 0000000..17a462e --- /dev/null +++ b/drmsrc/src/gstdrmsrc.c @@ -0,0 +1,604 @@ +/* + * drmsrc + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * 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 "gstdrmsrc.h" + +#define LOG_TRACE(message) //g_print("DRM_SRC: %s: %d: %s - %s \n", __FILE__, __LINE__, __FUNCTION__, message); + +#define GST_TAG_PLAYREADY "playready_file_path" + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,GST_STATIC_CAPS_ANY); + + +GST_DEBUG_CATEGORY_STATIC (gst_drm_src_debug); +#define GST_CAT_DEFAULT gst_drm_src_debug + +enum +{ + ARG_0, + ARG_LOCATION, + ARG_FD +}; +static void gst_drm_src_finalize (GObject * object); +static void gst_drm_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); +static void gst_drm_src_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); +static gboolean gst_drm_src_start (GstBaseSrc * basesrc); +static gboolean gst_drm_src_stop (GstBaseSrc * basesrc); +static gboolean gst_drm_src_is_seekable (GstBaseSrc * src); +static gboolean gst_drm_src_get_size (GstBaseSrc * src, guint64 * size); +static GstFlowReturn gst_drm_src_create (GstBaseSrc * src, guint64 offset, guint length, GstBuffer ** buffer); +static void gst_drm_src_uri_handler_init (gpointer g_iface, gpointer iface_data); + +G_DEFINE_TYPE_WITH_CODE (GstDrmSrc, gst_drm_src, GST_TYPE_BASE_SRC, + G_IMPLEMENT_INTERFACE(GST_TYPE_URI_HANDLER, gst_drm_src_uri_handler_init)); +/** + * This function does the following: + * 1. Sets the class details + * 2. Adds the source pad template + * + * @param g_class [out] gpointer + * + * @return void + */ +static void gst_drm_src_base_init (gpointer g_class) +{ +} +/** + * This function does the following: + * 1. Installs the properties + * 2. Assigns the function pointers GObject class attributes + * + * @param klass [out] GstDrmSrcClass Structure + * + * @return void + */ +static void gst_drm_src_class_init (GstDrmSrcClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSrcClass *gstbasesrc_class; + gobject_class = G_OBJECT_CLASS (klass); + gstelement_class= GST_ELEMENT_CLASS (klass); + gstbasesrc_class = GST_BASE_SRC_CLASS (klass); + // Assigns the function pointers GObject class attributes + gobject_class->set_property = gst_drm_src_set_property; + gobject_class->get_property = gst_drm_src_get_property; + // 1. Installs the properties + g_object_class_install_property (gobject_class, ARG_FD, + g_param_spec_int ("fd", "File-descriptor", + "File-descriptor for the file being mmap()d", 0, G_MAXINT, 0, + G_PARAM_READABLE)); + g_object_class_install_property (gobject_class, ARG_LOCATION, + g_param_spec_string ("location", "File Location", + "Location of the file to read", NULL, G_PARAM_READWRITE)); + + // 2. Sets the class details + gst_element_class_set_details_simple (gstelement_class, + "DRM Source", + "Source/File", + "Read from arbitrary point in a standard/DRM file", + "Kishore Arepalli and Sadanand Dodawadakar "); + // 3. Adds the source pad template + gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&srctemplate)); + // 4. Assigns the function pointers GObject class attributes + gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_drm_src_finalize); + gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_drm_src_start); + gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_drm_src_stop); + gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_drm_src_is_seekable); + gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_drm_src_get_size); + gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_drm_src_create); + + + gst_tag_register (GST_TAG_PLAYREADY, GST_TAG_FLAG_META, + G_TYPE_STRING, + "PlayReady File Path", + "a tag that is specific to PlayReady File", + NULL); +} +/** + * This function does the following: + * 1. Initilizes the parameters of GstDrmSrc + * + * @param src [out] GstDrmSrc structure + * @param g_class [in] GstDrmSrcClass structure + * + * @return gboolean Returns TRUE on success and FALSE on ERROR + */ +static void gst_drm_src_init (GstDrmSrc * src) +{ + // 1. Initilizes the parameters of GstDrmSrc + src->filename = NULL; + src->fd = 0; + src->uri = NULL; + src->is_regular = FALSE; + src->seekable = FALSE; +} +/** + * This function does the following: + * 1. deallocates the filename and uri + * 2. calls the parent class->finalize + * + * @param object [in] GObject Structure + * + * @return void + */ +static void gst_drm_src_finalize (GObject * object) +{ + GstDrmSrc *src; + + src = GST_DRM_SRC (object); + // 1. deallocates the filename and uri + g_free (src->filename); + g_free (src->uri); + // 2. calls the parent class->finalize + G_OBJECT_CLASS (gst_drm_src_parent_class)->finalize (object); +} +/** + * This function does the following: + * 1. Checks the state + * 2. Checks the filename + * 3. Sets the filename + * + * @param src [in] GstDrmSrc Structure + * @param location [in] location of the file + * + * @return gboolean Returns TRUE on success and FALSE on ERROR + */ +static gboolean gst_drm_src_set_location (GstDrmSrc * src, const gchar * location) +{ + GstState state; + + GST_OBJECT_LOCK (src); + // 1. Checks the state + state = GST_STATE (src); + if (state != GST_STATE_READY && state != GST_STATE_NULL) + { + GST_DEBUG_OBJECT (src, "setting location in wrong state"); + GST_OBJECT_UNLOCK (src); + return FALSE; + } + GST_OBJECT_UNLOCK (src); + g_free (src->filename); + g_free (src->uri); + // 2. Checks the filename + if (location == NULL) + { + src->filename = NULL; + src->uri = NULL; + } + else + { + // 3. Sets the filename + src->filename = g_strdup (location); + src->uri = gst_uri_construct ("file", src->filename); + } + g_object_notify (G_OBJECT (src), "location"); + return TRUE; +} +/** + * This function does the following: + * 1. Sets the location of the file. + * + * @param object [in] GObject Structure + * @param prop_id [in] id of the property + * @param value [in] property value + * @param pspec [in] GParamSpec Structure + * + * @return void + */ +static void gst_drm_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstDrmSrc *src; + + g_return_if_fail (GST_IS_DRM_SRC (object)); + src = GST_DRM_SRC (object); + switch (prop_id) + { + // 1. Sets the location of the file. + case ARG_LOCATION: + gst_drm_src_set_location (src, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} +/** + * This function does the following: + * 1. Provides the location of the file. + * 2. Provides the file descriptor. + * + * @param object [in] GObject Structure + * @param prop_id [in] id of the property + * @param value [out] property value + * @param pspec [in] GParamSpec Structure + * + * @return void + */ +static void gst_drm_src_get_property (GObject * object, guint prop_id, GValue * value,GParamSpec * pspec) +{ + GstDrmSrc *src; + + g_return_if_fail (GST_IS_DRM_SRC (object)); + src = GST_DRM_SRC (object); + switch (prop_id) + { + // 1. Provides the location of the file. + case ARG_LOCATION: + g_value_set_string (value, src->filename); + break; + // 2. Provides the file descriptor. + case ARG_FD: + g_value_set_int (value, src->fd); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/** + * This function does the following: + * 1. Seeks to the specified position. + * 2. Allocates a buffer to push the data + * 3. Reads from the file and sets the related params + * + * @param src [in] GstDrmSrc Structure + * @param offset [in] offset of the file to seek + * @param length [in] size of the data in bytes + * @param buffer [out] GstBuffer to hold the contents + * + * @return GstFlowReturn Returns GST_FLOW_OK on success and ERROR on failure + */ +static GstFlowReturn gst_drm_src_create_read (GstDrmSrc * src, guint64 offset, guint length, GstBuffer ** buffer) +{ + int ret; + GstBuffer *buf; + GstMapInfo buf_info = GST_MAP_INFO_INIT; + // 1. Seeks to the specified position. + if (G_UNLIKELY (src->read_position != offset)) + { + off_t res; + res = lseek (src->fd, offset, SEEK_SET); + if (G_UNLIKELY (res < 0 || res != offset)) + { + GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM); + return GST_FLOW_ERROR; + } + src->read_position = offset; + } + // 2. Allocates a buffer to push the data + buf = gst_buffer_new_and_alloc (length); + GST_LOG_OBJECT (src, "Reading %d bytes", length); + // 3. Reads from the file and sets the related params + gst_buffer_map(buf, &buf_info, GST_MAP_WRITE); + ret = read (src->fd, buf_info.data, length); + gst_buffer_unmap(buf, &buf_info); + if (G_UNLIKELY (ret < 0)) + { + GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM); + gst_buffer_unref (buf); + return GST_FLOW_ERROR; + } + if (G_UNLIKELY ((guint) ret < length && src->seekable)) + { + GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),("unexpected end of file.")); + gst_buffer_unref (buf); + return GST_FLOW_ERROR; + } + if (G_UNLIKELY (ret == 0 && length > 0)) + { + GST_DEBUG ("non-regular file hits EOS"); + gst_buffer_unref (buf); + return GST_FLOW_EOS; + } + length = ret; + GST_BUFFER_OFFSET (buf) = offset; + GST_BUFFER_OFFSET_END (buf) = offset + length; + *buffer = buf; + src->read_position += length; + return GST_FLOW_OK; +} +/** + * This function does the following: + * 1. Calls DRM file read chain method for drm files. + * 2. Calls normal file read chain method for standard files. + * + * @param basesrc [in] BaseSrc Structure + * @param size [out] Size of the file + * + * @return gboolean Returns TRUE on success and FALSE on ERROR + */ +static GstFlowReturn gst_drm_src_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer) +{ + GstDrmSrc *src = GST_DRM_SRC (basesrc); + + // 1. Calls DRM file read chain method for drm files. + + // 2. Calls normal file read chain method for standard files. + return gst_drm_src_create_read (src, offset, length, buffer); +} +/** + * + * @param basesrc [in] BaseSrc Structure + * + * @return gboolean Returns TRUE if the file is seekable and FALSE if the file is not seekable + */ +static gboolean gst_drm_src_is_seekable (GstBaseSrc * basesrc) +{ + GstDrmSrc *src = GST_DRM_SRC (basesrc); + return src->seekable; +} +/** + * This function does the following: + * 1. Gets the filesize for drm file by using seek oprations + * 2. Gets the file size for standard file by using statistics + * + * @param basesrc [in] BaseSrc Structure + * @param size [in] Size of the file + * + * @return gboolean Returns TRUE on success and FALSE on ERROR + */ +static gboolean gst_drm_src_get_size (GstBaseSrc * basesrc, guint64 * size) +{ + struct stat stat_results; + GstDrmSrc *src = GST_DRM_SRC (basesrc); + unsigned int offset; + + // 1. Gets the filesize for drm file by using seek oprations + + // 2. Gets the file size for standard file by using statistics + if (fstat (src->fd, &stat_results) < 0) + return FALSE; + *size = stat_results.st_size; + return TRUE; +} +/** + * This function does the following: + * 1. Checks the filename + * 2. Opens the file and check statistics of the file + * 7. Checks the seeking for standard files + * + * @param basesrc [in] BaseSrc Structure + * + * @return gboolean Returns TRUE on success and FALSE on ERROR + */ +static gboolean gst_drm_src_start (GstBaseSrc * basesrc) +{ + GstDrmSrc *src = GST_DRM_SRC (basesrc); + struct stat stat_results; + off_t ret; + // 1. Checks the filename + if (src->filename == NULL || src->filename[0] == '\0') + { + GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,("No file name specified for reading."), (NULL)); + return FALSE; + } + // 2. Opens the file and check statistics of the file + GST_INFO_OBJECT (src, "opening file %s", src->filename); + src->fd = open (src->filename, O_RDONLY | O_BINARY); + if (src->fd < 0) + { + if(errno == ENOENT) + { + GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),("No such file \"%s\"", src->filename)); + return FALSE; + } + GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, ("Could not open file \"%s\" for reading.", src->filename), GST_ERROR_SYSTEM); + return FALSE; + } + if (fstat (src->fd, &stat_results) < 0) + { + GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, ("Could not get info on \"%s\".", src->filename), (NULL)); + close (src->fd); + return FALSE; + } + if (S_ISDIR (stat_results.st_mode)) + { + GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, ("\"%s\" is a directory.", src->filename), (NULL)); + close (src->fd); + return FALSE; + } + if (S_ISSOCK (stat_results.st_mode)) + { + GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, ("File \"%s\" is a socket.", src->filename), (NULL)); + close (src->fd); + return FALSE; + } + src->read_position = 0; + + // 7. Checks the seeking for standard files + if (S_ISREG (stat_results.st_mode)) + src->is_regular = TRUE; + ret = lseek (src->fd, 0, SEEK_END); + if (ret < 0) + { + GST_LOG_OBJECT (src, "disabling seeking, not in mmap mode and lseek " + "failed: %s", g_strerror (errno)); + src->seekable = FALSE; + } + else + { + src->seekable = TRUE; + } + lseek (src->fd, 0, SEEK_SET); + src->seekable = src->seekable && src->is_regular; + return TRUE; +} +/** + * This function does the following: + * 1. Closes the file desciptor and resets the flags + * + * @param basesrc [in] BaseSrc Structure + * + * @return gboolean Returns TRUE on success and FALSE on ERROR + */ +static gboolean gst_drm_src_stop (GstBaseSrc * basesrc) +{ + GstDrmSrc *src = GST_DRM_SRC (basesrc); + + // 1. Closes the file desciptor and resets the flags + if(src->fd > 0) + close (src->fd); + src->fd = 0; + src->is_regular = FALSE; + return TRUE; +} +/** + * + * @param void + * + * @return GstURIType Returns GST_URI_SRC + */ + +static GstURIType gst_drm_src_uri_get_type (GType type) +{ + return GST_URI_SRC; +} + +/** + * This function does the following: + * 1. Defines the list of protocols + * + * @param void + * + * @return gchar ** Returns the protocol list + */ + +static const gchar * const* gst_drm_src_uri_get_protocols (GType type) +{ + static const gchar *protocols[] = { "file", NULL }; + return protocols; +} +/** + * + * @param handler [in] GstURIHandler structure + * + * @return gchar* Returns the uri + */ +static gchar * gst_drm_src_uri_get_uri (GstURIHandler *handler) +{ + GstDrmSrc *src = GST_DRM_SRC (handler); + return g_strdup(src->uri); +} +/** + * This function does the following: + * 1. Checks the protocol + * 2. Checks the whether it is absolute or not + * 3 sets the location + * + * @param handler [in] GstURIHandler structure + * @param uri [in] uri string + * + * @return gboolean Returns TRUE on success and FALSE on Error + */ +static gboolean gst_drm_src_uri_set_uri (GstURIHandler *handler, const gchar * uri,GError ** error) +{ + gchar *protocol, *location; + gboolean ret; + GstDrmSrc *src = GST_DRM_SRC (handler); + // 1. Checks the protocol + protocol = gst_uri_get_protocol (uri); + if (strcmp (protocol, "file") != 0) + { + g_free (protocol); + return FALSE; + } + g_free (protocol); + if (g_str_has_prefix (uri, "file://localhost/")) + { + char *tmp; + tmp = g_strconcat ("file://", uri + 16, NULL); + location = gst_uri_get_location (tmp); + g_free (tmp); + } + else if (strcmp (uri, "file://") == 0) + { + gst_drm_src_set_location (src, NULL); + return TRUE; + } + else + { + location = gst_uri_get_location (uri); + } + if (!location) + return FALSE; + // 2. Checks the whether it is absolute or not + if (!g_path_is_absolute (location)) + { + g_free (location); + return FALSE; + } + // 3 sets the location + ret = gst_drm_src_set_location (src, location); + g_free (location); + return ret; +} +/** + * This function does the following: + * 1. Assignes the function pointer for URI related stuff + * + * @param g_iface [in] an interface to URI handler + * @param iface_data [in] a gpointer + * + * @return void + */ +static void gst_drm_src_uri_handler_init (gpointer g_iface, gpointer iface_data) +{ + GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; + // 1. Assigning the function pointer for URI related stuff + iface->get_type = gst_drm_src_uri_get_type; + iface->get_protocols = gst_drm_src_uri_get_protocols; + iface->get_uri = gst_drm_src_uri_get_uri; + iface->set_uri = gst_drm_src_uri_set_uri; +} +/** + * This function does the following: + * 1. Registers an element as drmsrc + * + * @param i_pPlugin [in] a plug-in structure + * + * @return gboolean TRUE on SUCCESS and FALSE on Error + */ +static gboolean plugin_init(GstPlugin* i_pPlugin) +{ + return gst_element_register(i_pPlugin, "drmsrc", GST_RANK_NONE, GST_TYPE_DRM_SRC);; +} +/** + * This function does the following: + * 1. plugin defination + * + */ +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + drmsrc, + "Plugin to read data from standad/DRM File", + plugin_init, + VERSION, + "LGPL", + "Samsung Electronics Co", + "http://www.samsung.com/") + diff --git a/drmsrc/src/gstdrmsrc.h b/drmsrc/src/gstdrmsrc.h new file mode 100755 index 0000000..44a7395 --- /dev/null +++ b/drmsrc/src/gstdrmsrc.h @@ -0,0 +1,82 @@ +/* + * drmsrc + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * 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_DRM_SRC_H__ +#define __GST_DRM_SRC_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef S_ISREG +#define S_ISREG(mode) ((mode)&_S_IFREG) +#endif +#ifndef S_ISDIR +#define S_ISDIR(mode) ((mode)&_S_IFDIR) +#endif +#ifndef S_ISSOCK +#define S_ISSOCK(x) (0) +#endif +#ifndef O_BINARY +#define O_BINARY (0) +#endif + +G_BEGIN_DECLS + +#define GST_TYPE_DRM_SRC (gst_drm_src_get_type()) +#define GST_DRM_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DRM_SRC,GstDrmSrc)) +#define GST_DRM_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DRM_SRC,GstDrmSrcClass)) +#define GST_IS_DRM_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DRM_SRC)) +#define GST_IS_DRM_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DRM_SRC)) + +typedef struct _GstDrmSrc GstDrmSrc; +typedef struct _GstDrmSrcClass GstDrmSrcClass; + +struct _GstDrmSrc +{ + GstBaseSrc element; + gchar *filename; + gchar *uri; + gint fd; + guint64 read_position; + gboolean seekable; + gboolean is_regular; +}; + +struct _GstDrmSrcClass +{ + GstBaseSrcClass parent_class; +}; + +GType gst_drm_src_get_type (void); + +G_END_DECLS + +#endif /* __GST_DRM_SRC_H__ */ diff --git a/encodebin/Makefile.am b/encodebin/Makefile.am new file mode 100644 index 0000000..308a09c --- /dev/null +++ b/encodebin/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/encodebin/src/Makefile.am b/encodebin/src/Makefile.am new file mode 100644 index 0000000..c855890 --- /dev/null +++ b/encodebin/src/Makefile.am @@ -0,0 +1,30 @@ +glib_enum_define=GST_RECORD +glib_enum_prefix=gst_record + +plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@ + +plugin_LTLIBRARIES = libgstencodebin.la +libgstencodebin_la_SOURCES = gstencodebin.c +nodist_libgstencodebin_la_SOURCES = $(built_sources) +libgstencodebin_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +libgstencodebin_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstencodebin_la_LIBADD = \ + $(GST_LIBS)\ + $(GST_BASE_LIBS) \ + $(GST_LIBS) +if ISPROTECTOR_TARGET +libgstencodebin_la_CFLAGS += -DUSE_ENCODER_QUEUE_SET +libgstencodebin_la_CFLAGS += -DVIDEO_ENC_QUE_TIME=4 -DAUDIO_ENC_QUE_TIME=4 +endif + +if ISVOLANS_TARGET +libgstencodebin_la_CFLAGS += -DUSE_ENCODER_QUEUE_SET +libgstencodebin_la_CFLAGS += -DVIDEO_ENC_QUE_TIME=4 -DAUDIO_ENC_QUE_TIME=4 +endif + +BUILT_SOURCES = $(built_headers) $(built_sources) + +CLEANFILES = $(BUILT_SOURCES) + +include $(top_srcdir)/common/glib-gen.mak + diff --git a/encodebin/src/gstencodebin.c b/encodebin/src/gstencodebin.c new file mode 100644 index 0000000..f37aa75 --- /dev/null +++ b/encodebin/src/gstencodebin.c @@ -0,0 +1,3003 @@ +/* + * GStreamer encodebin + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * 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 +#include +#include + +#include "gstencodebin.h" + +#ifdef GST_EXT_PAD_LINK_UNCHECKED +#define _GST_ELEMENT_LINK_MANY gst_element_link_many_unchecked +#define _GST_ELEMENT_LINK gst_element_link_unchecked +#define _GST_PAD_LINK gst_pad_link_unchecked +#else +#define _GST_ELEMENT_LINK_MANY gst_element_link_many +#define _GST_ELEMENT_LINK gst_element_link +#define _GST_PAD_LINK gst_pad_link +#endif + +#ifndef VIDEO_ENC_QUE_TIME +#define VIDEO_ENC_QUE_TIME 1 +#endif +#ifndef AUDIO_ENC_QUE_TIME +#define AUDIO_ENC_QUE_TIME 1 +#endif + +//define USE_ENCODER_QUEUE_SET +#ifdef USE_ENCODER_QUEUE_SET +#define ENCODER_QUEUE_SET(x_queue, x_byte, x_buffer, x_time /*sec*/) \ +{\ +g_object_set(G_OBJECT(x_queue), \ + "max-size-bytes", (guint)x_byte, \ + "max-size-buffers", (guint)x_buffer, \ + "max-size-time", (guint64)(x_time*GST_SECOND), \ + NULL); \ + GST_INFO("Set to [%s], max [%d] byte, max [%d] buffer, max [%d] time(sec) ", GST_OBJECT_NAME(x_queue), x_byte, x_buffer, x_time);\ +} +#else +#define ENCODER_QUEUE_SET(x_queue, x_byte, x_buffer, x_time) +#endif + +#define _GST_PAD_LINK_UNREF( srcpad, sinkpad, if_fail_goto )\ +{\ + GstPadLinkReturn ret = _GST_PAD_LINK( srcpad, sinkpad );\ + gst_object_unref( srcpad ); srcpad = NULL;\ + gst_object_unref( sinkpad ); sinkpad = NULL;\ + if( ret != GST_PAD_LINK_OK) goto if_fail_goto;\ +} + +#define _GST_PAD_UNLINK_UNREF( srcpad, sinkpad)\ +{\ + gst_pad_unlink( srcpad, sinkpad );\ + gst_object_unref( srcpad ); srcpad = NULL;\ + gst_object_unref( sinkpad ); sinkpad = NULL;\ +} + +#define DEFAULT_PROP_PROFILE 0 +#define DEFAULT_PROP_HIGH_SPEED 0 +#define DEFAULT_PROP_VENC_NAME "avenc_h263" +#define DEFAULT_PROP_AENC_NAME "secenc_amr" +#define DEFAULT_PROP_IENC_NAME "jpegenc" +#define DEFAULT_PROP_MUX_NAME "avmux_3gp" +#define DEFAULT_PROP_VCONV_NAME "videoconvert" + +/* props */ +enum +{ + PROP_0, + // encodebin mode : a/v, audio only, stillshot + PROP_PROFILE, + //support slow motion capture + PROP_HIGH_SPEED, + //elements name + PROP_VENC_NAME, + PROP_AENC_NAME, + PROP_IENC_NAME, + PROP_MUX_NAME, + PROP_VCONV_NAME, + //caps + PROP_VCAPS, + PROP_ACAPS, + PROP_ICAPS, + //functions + PROP_AUTO_AUDIO_CONVERT, + PROP_AUTO_AUDIO_RESAMPLE, + PROP_AUTO_COLORSPACE, + PROP_BLOCK, + PROP_PAUSE, + PROP_VENC_QUEUE, + PROP_AENC_QUEUE, + //elements pointer + PROP_VIDEO_ENC, + PROP_AUDIO_ENC, + PROP_IMAGE_ENC, + PROP_MUX, + PROP_VIDEO_CONV, + //options + PROP_USE_VIDEO_TOGGLE, +}; + +#ifdef GST_ENCODE_BIN_SIGNAL_ENABLE +/* signals */ +enum +{ + SIGNAL_STREAM_BLOCK, + SIGNAL_STREAM_UNBLOCK, + SIGNAL_STREAM_PAUSE, + SIGNAL_STREAM_RESUME, + LAST_SIGNAL +}; +#endif + +typedef enum { + ENCODEBIN_ELEMENT_VENC, + ENCODEBIN_ELEMENT_AENC, + ENCODEBIN_ELEMENT_IENC, + ENCODEBIN_ELEMENT_MUX, + ENCODEBIN_ELEMENT_VIDEO_CONV +}GstEncodeBinElement; + +typedef enum { + ENCODEBIN_MUX_AUDIO_SINK, + ENCODEBIN_MUX_VIDEO_SINK, +}GstEncodeBinMuxSinkPad; + + +/* FIX ME */ + +#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) +# define ENDIANNESS "LITTLE_ENDIAN, BIG_ENDIAN" +#else +# define ENDIANNESS "BIG_ENDIAN, LITTLE_ENDIAN" +#endif + +/* generic templates */ +#define STATIC_AUDIO_CAPS \ +GST_STATIC_CAPS ( \ + "audio/x-raw, " \ + "format = (string) { F64LE, F64BE }, " \ + "rate = (int) [ 1, MAX ], " \ + "channels = (int) [ 1, 8 ]; " \ + "audio/x-raw, " \ + "format = (string) { F32LE, F32BE }, " \ + "rate = (int) [ 1, MAX ], " \ + "channels = (int) [ 1, 8 ]; " \ + "audio/x-raw, " \ + "format = (string) { S32LE, S32BE, U32LE, U32BE }, " \ + "rate = (int) [ 1, MAX ], " \ + "channels = (int) [ 1, 8 ]; " \ + "audio/x-raw, " \ + "format = (string) { S24LE, S24BE, U24LE, U24BE }, " \ + "rate = (int) [ 1, MAX ], " \ + "channels = (int) [ 1, 8 ]; " \ + "audio/x-raw, " \ + "format = (string) { S16LE, S16BE, U16LE, U16BE }, " \ + "rate = (int) [ 1, MAX ], " \ + "channels = (int) [ 1, 8 ]; " \ + "audio/x-raw, " \ + "format = (string) { S8, U8 }, " \ + "rate = (int) [ 1, MAX ], " \ + "channels = (int) [ 1, 8 ]; " \ +) + +#define STATIC_VIDEO_CAPS \ +GST_STATIC_CAPS ( \ + GST_VIDEO_CAPS_MAKE("I420") ";" \ + GST_VIDEO_CAPS_MAKE("YV12") ";" \ + GST_VIDEO_CAPS_MAKE("YUY2") ";" \ + GST_VIDEO_CAPS_MAKE("RGB") ";" \ + GST_VIDEO_CAPS_MAKE("BGR") ";" \ + GST_VIDEO_CAPS_MAKE("Y42B") ";" \ + GST_VIDEO_CAPS_MAKE("Y444") ";" \ + GST_VIDEO_CAPS_MAKE("BGRA") ";" \ + GST_VIDEO_CAPS_MAKE("ARGB") ";" \ + GST_VIDEO_CAPS_MAKE("ABGR") ";" \ + GST_VIDEO_CAPS_MAKE("RGBA") ";" \ + GST_VIDEO_CAPS_MAKE("BGRx") ";" \ + GST_VIDEO_CAPS_MAKE("xBGR") ";" \ + GST_VIDEO_CAPS_MAKE("xRGB") ";" \ + GST_VIDEO_CAPS_MAKE("RGBx") ";" \ + GST_VIDEO_CAPS_MAKE("YUV9") ";" \ + GST_VIDEO_CAPS_MAKE("YVU9") ";" \ + GST_VIDEO_CAPS_MAKE("Y41B") ";" \ + GST_VIDEO_CAPS_MAKE("RGB16") ";" \ + GST_VIDEO_CAPS_MAKE("RGB15") ";" \ + GST_VIDEO_CAPS_MAKE("GRAY8") ";" \ + GST_VIDEO_CAPS_MAKE("RGB8P") ";" \ + GST_VIDEO_CAPS_MAKE("UYVY") ";" \ + GST_VIDEO_CAPS_MAKE("IYU1") ";" \ + GST_VIDEO_CAPS_MAKE("AYUV") \ +) + + +static GstStaticPadTemplate encoder_bin_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +static GstStaticPadTemplate encoder_bin_video_sink_template = +GST_STATIC_PAD_TEMPLATE ("video", + GST_PAD_SINK, + GST_PAD_REQUEST, + STATIC_VIDEO_CAPS + ); + +static GstStaticPadTemplate encoder_bin_audio_sink_template = +GST_STATIC_PAD_TEMPLATE ("audio", + GST_PAD_SINK, + GST_PAD_REQUEST, + STATIC_AUDIO_CAPS + ); + +static GstStaticPadTemplate encoder_bin_image_sink_template = +GST_STATIC_PAD_TEMPLATE ("image", + GST_PAD_SINK, + GST_PAD_REQUEST, + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("I420")) + ); + +GST_DEBUG_CATEGORY_STATIC (gst_encode_bin_debug); +#define GST_CAT_DEFAULT gst_encode_bin_debug + +static void gst_encode_bin_class_init (GstEncodeBinClass *klass); +static void gst_encode_bin_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); +static void gst_encode_bin_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); +static void gst_encode_bin_init (GstEncodeBin * encodebin); +static void gst_encode_bin_dispose (GObject * object); +static void gst_encode_bin_finalize (GObject * object); +static GstPad *gst_encode_bin_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar* name, const GstCaps *caps); + +static GstStateChangeReturn gst_encode_bin_change_state (GstElement * element, GstStateChange transition); +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static void gst_encode_bin_release_pad (GstElement * element, GstPad * pad); +static gint pad_compare_name (GstPad * pad1, const gchar * name); +static gboolean gst_encode_bin_add_element_by_name (GstEncodeBin *encodebin, GstEncodeBinElement type, const gchar *name); +#if 0 //disable unused function +static gboolean gst_encode_bin_change_profile(GstEncodeBin *encodebin, gboolean profile); +static void gst_encode_bin_replace_element (GstEncodeBin *encodebin, gint type, GstElement * newelement); +static gboolean gst_encode_bin_replace_element_by_name(GstEncodeBin *encodebin, GstEncodeBinElement type, const gchar *name); +static gboolean gst_encode_bin_replace_element_by_object(GstEncodeBin *encodebin, GstEncodeBinElement type, GstElement * element); +#endif //disable unused function +static gboolean gst_encode_bin_remove_element (GstEncodeBin *encodebin, GstElement * element); +static gboolean gst_encode_bin_link_elements (GstEncodeBin *encodebin); +static gboolean gst_encode_bin_unlink_elements (GstEncodeBin *encodebin); +static gboolean gst_encode_bin_init_video_elements (GstElement *element, gpointer user_data); +static gboolean gst_encode_bin_init_audio_elements (GstElement *element, gpointer user_data); +static gboolean gst_encode_bin_init_image_elements (GstElement *element, gpointer user_data); +static gboolean gst_encode_bin_block(GstEncodeBin *encodebin, gboolean value); +static gboolean gst_encode_bin_pause(GstEncodeBin *encodebin, gboolean value); +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static gboolean gst_encode_bin_release_pipeline (GstElement *element, gpointer user_data); +static GstPad* gst_encode_bin_get_mux_sink_pad(GstElement *mux, GstEncodeBinMuxSinkPad type); + +//Data probe +static GstPadProbeReturn gst_encode_bin_video_probe(GstPad *pad, GstPadProbeInfo *info, GstEncodeBin *encodebin); +static GstPadProbeReturn gst_encode_bin_audio_probe(GstPad *pad, GstPadProbeInfo *info, GstEncodeBin *encodebin); +static GstPadProbeReturn gst_encode_bin_video_probe_hs(GstPad *pad, GstPadProbeInfo *info, GstEncodeBin *encodebin); + +static GstElementClass *parent_class; + +#ifdef GST_ENCODE_BIN_SIGNAL_ENABLE +static guint gst_encode_bin_signals[LAST_SIGNAL] = { 0 }; +#endif + +typedef enum { + GST_ENCODE_BIN_PROFILE_AV, + GST_ENCODE_BIN_PROFILE_AUDIO, + GST_ENCODE_BIN_PROFILE_IMAGE, +} GstEncodeBinProfile; + +GType +gst_encode_bin_profile_get_type (void) +{ + static GType encode_bin_profile_type = 0; + static const GEnumValue profile_types[] = { + {GST_ENCODE_BIN_PROFILE_AV, "Audio and Video Recording", "A/V"}, + {GST_ENCODE_BIN_PROFILE_AUDIO, "Audio Only Recording", "Audio"}, + {GST_ENCODE_BIN_PROFILE_IMAGE, "Image Stillshot", "Image"}, + {0, NULL, NULL} + }; + + if (!encode_bin_profile_type) { + encode_bin_profile_type = + g_enum_register_static ("GstEncodeBinProfile",profile_types); + } + return encode_bin_profile_type; +} + +GType +gst_encode_bin_get_type (void) +{ + static GType gst_encode_bin_type = 0; + + if (!gst_encode_bin_type) { + static const GTypeInfo gst_encode_bin_info = { + sizeof (GstEncodeBinClass), + NULL, + NULL, + (GClassInitFunc) gst_encode_bin_class_init, + NULL, + NULL, + sizeof (GstEncodeBin), + 0, + (GInstanceInitFunc) gst_encode_bin_init, + NULL + }; + + gst_encode_bin_type = + g_type_register_static (GST_TYPE_BIN, "GstEncodeBin", + &gst_encode_bin_info, 0); + } + + return gst_encode_bin_type; +} + +static void +queue_overun_cb (GstElement * queue, GstEncodeBin *encodebin) +{ +#if 0 + guint queue_size = 0; + guint queue_bufnum = 0; +// guint64 queue_time= (guint64)0; + + GstClockTime now = gst_util_get_timestamp (); + + g_object_get(G_OBJECT(queue), "current-level-bytes", &queue_size, + "current-level-buffers", &queue_bufnum, + // "current-level-time", &queue_time, + NULL); + GST_ELEMENT_WARNING (encodebin, STREAM, TOO_LAZY, + ("[%" GST_TIME_FORMAT "][%s], [%u b], [%u]", + GST_TIME_ARGS(now), GST_OBJECT_NAME(queue), queue_size, queue_bufnum), (NULL)); +#else + GST_ELEMENT_WARNING (encodebin, STREAM, TOO_LAZY, + ("%s overrun", GST_OBJECT_NAME(queue)), (NULL)); +#endif +} + +static void +gst_encode_bin_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstEncodeBin *encodebin; + + encodebin = GST_ENCODE_BIN (object); + + switch (prop_id) { + case PROP_PROFILE: + g_value_set_enum (value, encodebin->profile); + break; + case PROP_HIGH_SPEED: + g_value_set_int (value, encodebin->high_speed_fps); + break; + //elements name + case PROP_VENC_NAME: + g_value_set_string (value, encodebin->venc_name); + break; + case PROP_AENC_NAME: + g_value_set_string (value, encodebin->aenc_name); + break; + case PROP_IENC_NAME: + g_value_set_string (value, encodebin->ienc_name); + break; + case PROP_MUX_NAME: + g_value_set_string (value, encodebin->mux_name); + break; + case PROP_VCONV_NAME: + g_value_set_string (value, encodebin->vconv_name); + break; + //caps + case PROP_VCAPS: + gst_value_set_caps (value, encodebin->vcaps); + break; + case PROP_ACAPS: + gst_value_set_caps (value, encodebin->acaps); + break; + case PROP_ICAPS: + gst_value_set_caps (value, encodebin->icaps); + break; + //functions + case PROP_AUTO_AUDIO_CONVERT: + g_value_set_boolean (value, encodebin->auto_audio_convert); + break; + case PROP_AUTO_AUDIO_RESAMPLE: + g_value_set_boolean (value, encodebin->auto_audio_resample); + break; + case PROP_AUTO_COLORSPACE: + g_value_set_boolean (value, encodebin->auto_color_space); + break; + case PROP_BLOCK: + g_value_set_boolean (value, encodebin->block); + break; + case PROP_PAUSE: + g_value_set_boolean (value, encodebin->pause); + break; + case PROP_VENC_QUEUE: +// g_value_set_boolean (value, encodebin->use_venc_queue); + if((encodebin->video_encode_queue == NULL) && (encodebin->profile == GST_ENCODE_BIN_PROFILE_AV)) { + encodebin->video_encode_queue = gst_element_factory_make ("queue", "video_encode_queue"); + if(encodebin->video_encode_queue != NULL) + gst_bin_add(GST_BIN(encodebin), encodebin->video_encode_queue); + } + g_value_set_object (value, encodebin->video_encode_queue); + break; + case PROP_AENC_QUEUE: +// g_value_set_boolean (value, encodebin->use_aenc_queue); + if((encodebin->audio_encode_queue == NULL) && (encodebin->profile <= GST_ENCODE_BIN_PROFILE_AUDIO)) { + encodebin->audio_encode_queue = gst_element_factory_make ("queue", "audio_encode_queue"); + if(encodebin->audio_encode_queue != NULL) + gst_bin_add(GST_BIN(encodebin), encodebin->audio_encode_queue); + } + g_value_set_object (value, encodebin->audio_encode_queue); + break; + //elements pointer + case PROP_VIDEO_ENC: + if((encodebin->video_encode == NULL) && (encodebin->profile == GST_ENCODE_BIN_PROFILE_AV)) { + encodebin->video_encode = gst_element_factory_make (encodebin->venc_name, "video_encode"); + if(encodebin->video_encode != NULL) + gst_bin_add(GST_BIN(encodebin), encodebin->video_encode); + } + g_value_set_object (value, encodebin->video_encode); + break; + case PROP_AUDIO_ENC: + if(encodebin->audio_encode == NULL && (encodebin->profile <= GST_ENCODE_BIN_PROFILE_AUDIO)) { + encodebin->audio_encode = gst_element_factory_make (encodebin->aenc_name, "audio_encode"); + if(encodebin->audio_encode != NULL) + gst_bin_add(GST_BIN(encodebin), encodebin->audio_encode); + } + g_value_set_object (value, encodebin->audio_encode); + break; + case PROP_IMAGE_ENC: + if(encodebin->image_encode == NULL && (encodebin->profile == GST_ENCODE_BIN_PROFILE_IMAGE)) { + encodebin->image_encode = gst_element_factory_make (encodebin->ienc_name, "image_encode"); + if(encodebin->image_encode != NULL) + gst_bin_add(GST_BIN(encodebin), encodebin->image_encode); + } + g_value_set_object (value, encodebin->image_encode); + break; + case PROP_MUX: + if(encodebin->mux == NULL && (encodebin->profile <= GST_ENCODE_BIN_PROFILE_AUDIO)) { + encodebin->mux = gst_element_factory_make (encodebin->mux_name, "mux"); + if(encodebin->mux != NULL) + gst_bin_add(GST_BIN(encodebin), encodebin->mux); + } + g_value_set_object (value, encodebin->mux); + break; + case PROP_VIDEO_CONV: + if(encodebin->color_space == NULL && (encodebin->profile != GST_ENCODE_BIN_PROFILE_AUDIO)) { + encodebin->color_space = gst_element_factory_make (encodebin->vconv_name, "video_convert"); + if(encodebin->color_space != NULL) + gst_bin_add(GST_BIN(encodebin), encodebin->color_space); + } + g_value_set_object (value, encodebin->color_space); + break; + case PROP_USE_VIDEO_TOGGLE: + g_value_set_boolean( value, encodebin->use_video_toggle ); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_encode_bin_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstEncodeBin *encodebin; + + encodebin = GST_ENCODE_BIN (object); + + switch (prop_id) { + case PROP_PROFILE: + encodebin->profile = g_value_get_enum (value); + /* + gboolean newprofile = g_value_get_enum (value); + if(encodebin->profile != newprofile) { + gst_encode_bin_change_profile(encodebin, newprofile); + encodebin->profile = newprofile; + } + */ + break; + case PROP_HIGH_SPEED: + encodebin->high_speed_fps = g_value_get_int (value); + break; + case PROP_VENC_NAME: { + const gchar *new_name; + if(encodebin->profile > GST_ENCODE_BIN_PROFILE_AV) { + GST_WARNING_OBJECT(encodebin, "Profile isn't match, change profile first!"); + break; + } + new_name = g_value_get_string (value); + + if(encodebin->video_encode == NULL) { + if(gst_encode_bin_add_element_by_name(encodebin, ENCODEBIN_ELEMENT_VENC, new_name)) + encodebin->venc_name = g_strdup (new_name); + } else { + if(strcmp (encodebin->venc_name, new_name)) { + gst_encode_bin_remove_element(encodebin, encodebin->video_encode); + if(gst_encode_bin_add_element_by_name(encodebin, ENCODEBIN_ELEMENT_VENC, new_name)) + encodebin->venc_name = g_strdup (new_name); + } + } + break; + } + case PROP_AENC_NAME: { + const gchar *new_name; + if(encodebin->profile > GST_ENCODE_BIN_PROFILE_AUDIO) { + GST_WARNING_OBJECT(encodebin, "Profile isn't match, change profile first!"); + break; + } + new_name = g_value_get_string (value); + + if(encodebin->audio_encode == NULL) { + if(gst_encode_bin_add_element_by_name(encodebin, ENCODEBIN_ELEMENT_AENC, new_name)) + encodebin->aenc_name = g_strdup (new_name); + } else { + if(strcmp (encodebin->aenc_name, new_name)) { + gst_encode_bin_remove_element(encodebin, encodebin->audio_encode); + if(gst_encode_bin_add_element_by_name(encodebin, ENCODEBIN_ELEMENT_AENC, new_name)) + encodebin->aenc_name = g_strdup (new_name); + } + } + break; + } + case PROP_IENC_NAME: { + const gchar *new_name; + if(encodebin->profile < GST_ENCODE_BIN_PROFILE_IMAGE) { + GST_WARNING_OBJECT(encodebin, "Profile isn't match, change profile first!"); + break; + } + new_name = g_value_get_string (value); + + if(encodebin->image_encode == NULL) { + if(gst_encode_bin_add_element_by_name(encodebin, ENCODEBIN_ELEMENT_IENC, new_name)) + encodebin->ienc_name = g_strdup (new_name); + } else { + if(strcmp (encodebin->ienc_name, new_name)) { + gst_encode_bin_remove_element(encodebin, encodebin->image_encode); + if(gst_encode_bin_add_element_by_name(encodebin, ENCODEBIN_ELEMENT_IENC, new_name)) + encodebin->ienc_name = g_strdup (new_name); + } + } + break; + } + case PROP_MUX_NAME: { + const gchar *new_name; + if(encodebin->profile > GST_ENCODE_BIN_PROFILE_AUDIO) { + GST_WARNING_OBJECT(encodebin, "Profile isn't match"); + break; + } + new_name = g_value_get_string (value); + + if(encodebin->mux == NULL) { + if(gst_encode_bin_add_element_by_name(encodebin, ENCODEBIN_ELEMENT_MUX, new_name)) + encodebin->mux_name = g_strdup (new_name); + } else { + if(strcmp (encodebin->mux_name, new_name)) { + gst_encode_bin_remove_element(encodebin, encodebin->mux); + if(gst_encode_bin_add_element_by_name(encodebin, ENCODEBIN_ELEMENT_MUX, new_name)) + encodebin->mux_name = g_strdup (new_name); + } + } + break; + } + case PROP_VCONV_NAME: { + const gchar *new_name; + if (encodebin->profile == GST_ENCODE_BIN_PROFILE_AUDIO) { + GST_WARNING_OBJECT(encodebin, "Profile isn't match"); + break; + } + new_name = g_value_get_string(value); + + if (encodebin->color_space == NULL) { + if(gst_encode_bin_add_element_by_name(encodebin, ENCODEBIN_ELEMENT_VIDEO_CONV, new_name)) + encodebin->vconv_name = g_strdup (new_name); + } else { + if(strcmp (encodebin->vconv_name, new_name)) { + gst_encode_bin_remove_element(encodebin, encodebin->color_space); + if(gst_encode_bin_add_element_by_name(encodebin, ENCODEBIN_ELEMENT_VIDEO_CONV, new_name)) + encodebin->vconv_name = g_strdup (new_name); + } + } + break; + } + //caps + case PROP_VCAPS: { + GstCaps *new_caps; + GstCaps *old_caps; + const GstCaps *new_caps_val = gst_value_get_caps (value); + + if (new_caps_val == NULL) { + new_caps = gst_caps_new_any (); + } else { + new_caps = (GstCaps *) new_caps_val; + gst_caps_ref (new_caps); + } + + old_caps = encodebin->vcaps; + encodebin->vcaps = new_caps; + gst_caps_unref (old_caps); + break; + } + case PROP_ACAPS: { + GstCaps *new_caps; + GstCaps *old_caps; + const GstCaps *new_caps_val = gst_value_get_caps (value); + + if (new_caps_val == NULL) { + new_caps = gst_caps_new_any (); + } else { + new_caps = (GstCaps *) new_caps_val; + gst_caps_ref (new_caps); + } + + old_caps = encodebin->acaps; + encodebin->acaps = new_caps; + gst_caps_unref (old_caps); + break; + } + case PROP_ICAPS: { + GstCaps *new_caps; + GstCaps *old_caps; + const GstCaps *new_caps_val = gst_value_get_caps (value); + + if (new_caps_val == NULL) { + new_caps = gst_caps_new_any (); + } else { + new_caps = (GstCaps *) new_caps_val; + gst_caps_ref (new_caps); + } + + old_caps = encodebin->icaps; + encodebin->icaps = new_caps; + gst_caps_unref (old_caps); + break; + } + //functions + case PROP_AUTO_AUDIO_CONVERT: + encodebin->auto_audio_convert = g_value_get_boolean (value); + break; + case PROP_AUTO_AUDIO_RESAMPLE: + encodebin->auto_audio_resample = g_value_get_boolean (value); + break; + case PROP_AUTO_COLORSPACE: + encodebin->auto_color_space = g_value_get_boolean (value); + break; + case PROP_BLOCK: { + gboolean newval = g_value_get_boolean (value); + if(encodebin->block != newval) { + if(!gst_encode_bin_block(encodebin, newval)) { +#ifdef GST_ENCODE_BIN_SIGNAL_ENABLE + if(newval) { + g_signal_emit (G_OBJECT (encodebin), gst_encode_bin_signals[SIGNAL_STREAM_BLOCK], 0, FALSE); + } else { + g_signal_emit (G_OBJECT (encodebin), gst_encode_bin_signals[SIGNAL_STREAM_UNBLOCK], 0, FALSE); + } +#endif + break; + } + } +#ifdef GST_ENCODE_BIN_SIGNAL_ENABLE + if(newval) { + g_signal_emit (G_OBJECT (encodebin), gst_encode_bin_signals[SIGNAL_STREAM_BLOCK], 0, TRUE); + } else { + g_signal_emit (G_OBJECT (encodebin), gst_encode_bin_signals[SIGNAL_STREAM_UNBLOCK], 0, TRUE); + } +#endif + break; + } + case PROP_PAUSE: { + gboolean newval = g_value_get_boolean (value); + if(encodebin->pause != newval) { + if(!gst_encode_bin_pause(encodebin, newval)) + break; + } +#ifdef GST_ENCODE_BIN_SIGNAL_ENABLE + if(newval) { + g_signal_emit (G_OBJECT (encodebin), gst_encode_bin_signals[SIGNAL_STREAM_PAUSE], 0, TRUE); + } else { + g_signal_emit (G_OBJECT (encodebin), gst_encode_bin_signals[SIGNAL_STREAM_RESUME], 0, TRUE); + } +#endif + break; + } + case PROP_VENC_QUEUE: +// encodebin->use_venc_queue = g_value_get_boolean (value); + { + GstElement *newelement = g_value_get_object (value); + if(encodebin->profile > GST_ENCODE_BIN_PROFILE_AV) { + GST_WARNING_OBJECT(encodebin, "Profile isn't match, change profile first!"); + break; + } + if(newelement != NULL) { + gst_encode_bin_remove_element(encodebin, encodebin->video_encode_queue); + encodebin->video_encode_queue = newelement; + gst_object_ref_sink (GST_OBJECT_CAST (encodebin->video_encode_queue)); // take ownership ?? + gst_bin_add(GST_BIN(encodebin), encodebin->video_encode_queue); + } + break; + } + break; + case PROP_AENC_QUEUE: +// encodebin->use_aenc_queue = g_value_get_boolean (value); + { + GstElement *newelement = g_value_get_object (value); + if(encodebin->profile > GST_ENCODE_BIN_PROFILE_AUDIO) { + GST_WARNING_OBJECT(encodebin, "Profile isn't match, change profile first!"); + break; + } + if(newelement != NULL) { + gst_encode_bin_remove_element(encodebin, encodebin->audio_encode_queue); + encodebin->audio_encode_queue = newelement; + gst_object_ref_sink (GST_OBJECT_CAST (encodebin->audio_encode_queue)); + gst_bin_add(GST_BIN(encodebin), encodebin->audio_encode_queue); + } + break; + } + break; + case PROP_VIDEO_ENC: + { + GstElement *newelement = g_value_get_object (value); + if(encodebin->profile > GST_ENCODE_BIN_PROFILE_AV) { + GST_WARNING_OBJECT(encodebin, "Profile isn't match, change profile first!"); + break; + } + if(newelement != NULL) { + gst_encode_bin_remove_element(encodebin, encodebin->video_encode); + encodebin->video_encode = newelement; + gst_object_ref_sink (GST_OBJECT_CAST (encodebin->video_encode)); // take ownership ?? + gst_bin_add(GST_BIN(encodebin), encodebin->video_encode); + } + break; + } + case PROP_AUDIO_ENC: + { + GstElement *newelement = g_value_get_object (value); + if(encodebin->profile > GST_ENCODE_BIN_PROFILE_AUDIO) { + GST_WARNING_OBJECT(encodebin, "Profile isn't match, change profile first!"); + break; + } + if(newelement != NULL) { + gst_encode_bin_remove_element(encodebin, encodebin->audio_encode); + encodebin->audio_encode = newelement; + gst_object_ref_sink (GST_OBJECT_CAST (encodebin->audio_encode)); + gst_bin_add(GST_BIN(encodebin), encodebin->audio_encode); + } + break; + } + case PROP_IMAGE_ENC: { + GstElement *newelement = g_value_get_object (value); + if(encodebin->profile < GST_ENCODE_BIN_PROFILE_IMAGE) { + GST_WARNING_OBJECT(encodebin, "Profile isn't match, change profile first!"); + break; + } + if(newelement != NULL) { + gst_encode_bin_remove_element(encodebin, encodebin->image_encode); + encodebin->image_encode = newelement; + gst_object_ref_sink (GST_OBJECT_CAST (encodebin->image_encode)); + gst_bin_add(GST_BIN(encodebin), encodebin->image_encode); + } + break; + } + case PROP_MUX: { + GstElement *newelement = g_value_get_object (value); + if(encodebin->profile > GST_ENCODE_BIN_PROFILE_AUDIO) { + GST_WARNING_OBJECT(encodebin, "Profile isn't match, change profile first!"); + break; + } + if(newelement != NULL) { + gst_encode_bin_remove_element(encodebin, encodebin->mux); + encodebin->mux = newelement; + gst_object_ref_sink (GST_OBJECT_CAST (encodebin->mux)); + gst_bin_add(GST_BIN(encodebin), encodebin->mux); + } + break; + } + case PROP_VIDEO_CONV: { + GstElement *newelement = g_value_get_object (value); + if(encodebin->profile == GST_ENCODE_BIN_PROFILE_AUDIO) { + GST_WARNING_OBJECT(encodebin, "Profile isn't match, change profile first!"); + break; + } + if(newelement != NULL) { + gst_encode_bin_remove_element(encodebin, encodebin->color_space); + encodebin->color_space = newelement; + gst_object_ref_sink (GST_OBJECT_CAST (encodebin->color_space)); + gst_bin_add(GST_BIN(encodebin), encodebin->color_space); + } + break; + } + case PROP_USE_VIDEO_TOGGLE: + encodebin->use_video_toggle = g_value_get_boolean( value ); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstPad * +gst_encode_bin_request_new_pad (GstElement *element, GstPadTemplate *templ, + const gchar* name, const GstCaps *caps) +{ + GstEncodeBin *encodebin = NULL; + GstElementClass *klass = GST_ELEMENT_GET_CLASS (element); + GstPad *pad = NULL; + + g_return_val_if_fail (templ != NULL, NULL); + + if (templ->direction != GST_PAD_SINK) { + GST_WARNING_OBJECT (GST_IS_ENCODE_BIN (element), "encodebin: request pad that is not a SINK pad\n"); + return NULL; + } + + g_return_val_if_fail (GST_IS_ENCODE_BIN (element), NULL); + + encodebin = GST_ENCODE_BIN (element); + + /* FIXME */ + if (templ == gst_element_class_get_pad_template (klass, "audio")) { + if (encodebin->profile <= GST_ENCODE_BIN_PROFILE_AUDIO) { + gst_encode_bin_init_audio_elements(element, NULL); //?? + + if(encodebin->audio_sinkpad == NULL) + { + pad = gst_element_get_static_pad (encodebin->audio_queue, "sink"); + encodebin->audio_sinkpad = gst_ghost_pad_new ("audio", pad); + gst_object_unref(pad); + pad = NULL; + } + else + { + GST_WARNING_OBJECT (GST_IS_ENCODE_BIN (element), "encodebin: audio pad is aleady existed, return existing audio pad\n"); + return encodebin->audio_sinkpad; + } + + gst_element_add_pad (element, encodebin->audio_sinkpad); + return encodebin->audio_sinkpad; + } else + return NULL; + } else if (templ == gst_element_class_get_pad_template (klass, "video")) { + if (encodebin->profile == GST_ENCODE_BIN_PROFILE_AV) { + gst_encode_bin_init_video_elements(element, NULL); //?? + + if(encodebin->video_sinkpad == NULL) + { + pad = gst_element_get_static_pad (encodebin->video_queue, "sink"); + encodebin->video_sinkpad = gst_ghost_pad_new ("video", pad); + gst_object_unref(pad); + pad = NULL; + } + else + { + GST_WARNING_OBJECT (GST_IS_ENCODE_BIN (element), "encodebin: video pad is aleady existed, return existing video pad\n"); + return encodebin->video_sinkpad; + } + + gst_element_add_pad (element, encodebin->video_sinkpad); + return encodebin->video_sinkpad; + } else if (encodebin->profile == GST_ENCODE_BIN_PROFILE_IMAGE) { + gst_encode_bin_init_image_elements(element, NULL); //?? + + if(encodebin->image_sinkpad == NULL) + { + pad = gst_element_get_static_pad (encodebin->image_queue, "sink"); + encodebin->image_sinkpad = gst_ghost_pad_new ("image", pad); + gst_object_unref(pad); + pad = NULL; + } + else + { + GST_WARNING_OBJECT (GST_IS_ENCODE_BIN (element), "encodebin: image pad is aleady existed, return existing image pad\n"); + return encodebin->image_sinkpad; + } + + gst_element_add_pad (element, encodebin->image_sinkpad); + return encodebin->image_sinkpad; + } else + return NULL; + } else { + if (encodebin->profile == GST_ENCODE_BIN_PROFILE_IMAGE) { + gst_encode_bin_init_image_elements(element, NULL); //?? + + if(encodebin->image_sinkpad == NULL) + { + pad = gst_element_get_static_pad (encodebin->image_queue, "sink"); + encodebin->image_sinkpad = gst_ghost_pad_new ("image", pad); + gst_object_unref(pad); + pad = NULL; + } + else + { + GST_WARNING_OBJECT (GST_IS_ENCODE_BIN (element), "encodebin: image pad is aleady existed, return existing image pad\n"); + return encodebin->image_sinkpad; + } + + gst_element_add_pad (element, encodebin->image_sinkpad); + return encodebin->image_sinkpad; + } else + return NULL; + } +} + +static void +gst_encode_bin_class_init (GstEncodeBinClass *klass) +{ + GObjectClass *gobject_klass; + GstElementClass *gstelement_klass; + GstBinClass *gstbin_klass; + + gobject_klass = (GObjectClass *) klass; + gstelement_klass = (GstElementClass *) klass; + gstbin_klass = (GstBinClass *) klass; + + parent_class = g_type_class_peek_parent (klass); + + gobject_klass->get_property = gst_encode_bin_get_property; + gobject_klass->set_property = gst_encode_bin_set_property; + gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_encode_bin_dispose); + gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_encode_bin_finalize); + + + g_object_class_install_property (gobject_klass, PROP_PROFILE, + g_param_spec_enum ("profile", "PROFILE", "Profile of the media to record", + GST_TYPE_ENCODE_BIN_PROFILE, DEFAULT_PROP_PROFILE, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_HIGH_SPEED, + g_param_spec_int ("high-speed-fps", "high speed rec. fps", "framerate for high speed recording", 0, G_MAXINT, + DEFAULT_PROP_HIGH_SPEED, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_VENC_NAME, + g_param_spec_string ("venc-name", "video encoder name", "the name of video encoder to use", + DEFAULT_PROP_VENC_NAME, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_AENC_NAME, + g_param_spec_string ("aenc-name", "audio encoder name", "the name of audio encoder to use", + DEFAULT_PROP_AENC_NAME, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_IENC_NAME, + g_param_spec_string ("ienc-name", "image encoder name", "the name of image encoder to use", + DEFAULT_PROP_IENC_NAME, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_MUX_NAME, + g_param_spec_string ("mux-name", "muxer name", "the name of muxer to use", + DEFAULT_PROP_MUX_NAME, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_VCONV_NAME, + g_param_spec_string ("vconv-name", "Video converter name", "the name of video color converter to use", + DEFAULT_PROP_VCONV_NAME, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_VCAPS, + g_param_spec_boxed ("vcaps", "caps for video","caps for video recording", + GST_TYPE_CAPS, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_ACAPS, + g_param_spec_boxed ("acaps", "caps for audio","caps for audio recording", + GST_TYPE_CAPS, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_ICAPS, + g_param_spec_boxed ("icaps", "caps for image","caps for image stillshot", + GST_TYPE_CAPS, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_AUTO_AUDIO_CONVERT, + g_param_spec_boolean ("auto-audio-convert", "auto audio convert", + "Support for auto audio convert", TRUE, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_AUTO_AUDIO_RESAMPLE, + g_param_spec_boolean ("auto-audio-resample", "auto audio resample", + "Support for auto audio resample", TRUE, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_AUTO_COLORSPACE, + g_param_spec_boolean ("auto-colorspace", "auto colorspace", + "Support for auto colorspace", TRUE, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_BLOCK, + g_param_spec_boolean ("block", "stream block", + "Support for stream block", FALSE, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_PAUSE, + g_param_spec_boolean ("runtime-pause", "recording pause", + "Support for recording pause/resume", FALSE, G_PARAM_READWRITE)); + +#if 0 + g_object_class_install_property (gobject_klass, PROP_VENC_QUEUE, + g_param_spec_boolean ("use-venc-queue", "use queue between venc and mux", + "add queue between venc and mux(only for custom optimization)", FALSE, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_AENC_QUEUE, + g_param_spec_boolean ("use-aenc-queue", "use queue between aenc and mux", + "add queue between aenc and mux(only for custom optimization)", FALSE, G_PARAM_READWRITE)); +#else + g_object_class_install_property (gobject_klass, PROP_VENC_QUEUE, + g_param_spec_object ("use-venc-queue", "Video Encoder queue", + "add queue between venc and mux(only for custom optimization)", + GST_TYPE_ELEMENT, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_AENC_QUEUE, + g_param_spec_object ("use-aenc-queue", "Audio Encoder queue", + "add queue between aenc and mux(only for custom optimization)", + GST_TYPE_ELEMENT, G_PARAM_READWRITE)); +#endif + + g_object_class_install_property (gobject_klass, PROP_VIDEO_ENC, + g_param_spec_object ("video-encode", "Video Encoder", + "the video encoder element to use", + GST_TYPE_ELEMENT, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_AUDIO_ENC, + g_param_spec_object ("audio-encode", "Audio Encoder", + "the audio encoder element to use", + GST_TYPE_ELEMENT, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_IMAGE_ENC, + g_param_spec_object ("image-encode", "Image Encoder", + "the Image encoder element to use", + GST_TYPE_ELEMENT, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_MUX, + g_param_spec_object ("mux", "Muxer", + "the muxer element to use", + GST_TYPE_ELEMENT, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_VIDEO_CONV, + g_param_spec_object ("video-convert", "Video converter", + "the video converter element to use", + GST_TYPE_ELEMENT, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_klass, PROP_USE_VIDEO_TOGGLE, + g_param_spec_boolean ("use-video-toggle", "Use video toggle", + "Use video toggle while AV recording", TRUE, G_PARAM_READWRITE)); + +#ifdef GST_ENCODE_BIN_SIGNAL_ENABLE + gst_encode_bin_signals[SIGNAL_STREAM_BLOCK] = + g_signal_new ("stream-block", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstEncodeBinClass, stream_block), + NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + + gst_encode_bin_signals[SIGNAL_STREAM_UNBLOCK] = + g_signal_new ("stream-unblock", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstEncodeBinClass, stream_unblock), + NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + + gst_encode_bin_signals[SIGNAL_STREAM_PAUSE] = + g_signal_new ("stream-pause", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstEncodeBinClass, stream_pause), + NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + + gst_encode_bin_signals[SIGNAL_STREAM_RESUME] = + g_signal_new ("stream-resume", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstEncodeBinClass, stream_resume), + NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); +#endif + + gst_element_class_add_pad_template (gstelement_klass, + gst_static_pad_template_get (&encoder_bin_src_template)); + gst_element_class_add_pad_template (gstelement_klass, + gst_static_pad_template_get (&encoder_bin_audio_sink_template)); + gst_element_class_add_pad_template (gstelement_klass, + gst_static_pad_template_get (&encoder_bin_video_sink_template)); + gst_element_class_add_pad_template (gstelement_klass, + gst_static_pad_template_get (&encoder_bin_image_sink_template)); + + gst_element_class_set_static_metadata(gstelement_klass, "Samsung Electronics Co. Encoder Bin", + "Generic/Bin/Encoder", + "Autoplug and encode to muxed media", + "Jeonghoon Park , Wonhyung Cho , Sangho Park "); + + gstelement_klass->request_new_pad = + GST_DEBUG_FUNCPTR (gst_encode_bin_request_new_pad); + gstelement_klass->release_pad = + GST_DEBUG_FUNCPTR (gst_encode_bin_release_pad); + gstelement_klass->change_state = + GST_DEBUG_FUNCPTR (gst_encode_bin_change_state); +} + +static void +gst_encode_bin_init (GstEncodeBin *encodebin) +{ + encodebin->mutex = g_mutex_new(); + + if (encodebin->srcpad == NULL) { + encodebin->srcpad = gst_ghost_pad_new_no_target ("src", GST_PAD_SRC); + gst_element_add_pad (GST_ELEMENT(encodebin), encodebin->srcpad); + } + + encodebin->video_sinkpad = NULL; + encodebin->audio_sinkpad = NULL; + encodebin->image_sinkpad = NULL; + encodebin->mux_audio_sinkpad = NULL; + encodebin->mux_video_sinkpad = NULL; + + encodebin->profile = DEFAULT_PROP_PROFILE; + encodebin->fps = 0; + encodebin->high_speed_fps = DEFAULT_PROP_HIGH_SPEED; + encodebin->multiple = 1; + + encodebin->auto_audio_convert = TRUE; + encodebin->auto_audio_resample = TRUE; + encodebin->auto_color_space = TRUE; + encodebin->block = FALSE; + encodebin->pause= FALSE; + encodebin->use_video_toggle = TRUE; + encodebin->use_venc_queue= FALSE; + encodebin->use_aenc_queue= FALSE; + + encodebin->venc_name = g_strdup(DEFAULT_PROP_VENC_NAME); + encodebin->aenc_name = g_strdup(DEFAULT_PROP_AENC_NAME); + encodebin->ienc_name = g_strdup(DEFAULT_PROP_IENC_NAME); + encodebin->mux_name = g_strdup(DEFAULT_PROP_MUX_NAME); + encodebin->vconv_name = g_strdup(DEFAULT_PROP_VCONV_NAME); + + encodebin->vcaps = gst_caps_new_any (); + encodebin->acaps = gst_caps_new_any (); + encodebin->icaps = gst_caps_new_any (); + + encodebin->audio_queue = NULL; + encodebin->video_queue = NULL; + encodebin->video_encode_queue = NULL; + encodebin->image_queue = NULL; + + encodebin->audio_encode = NULL; + encodebin->video_encode = NULL; + encodebin->image_encode = NULL; + + encodebin->vcapsfilter = NULL; + encodebin->acapsfilter = NULL; + encodebin->icapsfilter = NULL; + + encodebin->video_toggle = NULL; + encodebin->image_toggle = NULL; + encodebin->color_space = NULL; + encodebin->audio_conv = NULL; + encodebin->audio_sample = NULL; + + encodebin->mux = NULL; + + encodebin->paused_time = 0; + encodebin->total_offset_time = 0; + + encodebin->vsink_probeid = 0; + encodebin->vsink_hs_probeid = 0; + encodebin->asink_probeid = 0; + encodebin->veque_sig_id = 0; + encodebin->aeque_sig_id = 0; +} + +static void +gst_encode_bin_dispose (GObject * object) +{ + GstEncodeBin *encodebin = GST_ENCODE_BIN (object); + + g_free(encodebin->venc_name); + encodebin->venc_name = NULL; + + g_free(encodebin->aenc_name); + encodebin->aenc_name = NULL; + + g_free(encodebin->ienc_name); + encodebin->ienc_name = NULL; + + g_free(encodebin->mux_name); + encodebin->mux_name = NULL; + + g_free(encodebin->vconv_name); + encodebin->vconv_name = NULL; + + gst_caps_replace (&encodebin->vcaps, NULL); + gst_caps_replace (&encodebin->acaps, NULL); + gst_caps_replace (&encodebin->icaps, NULL); + + if (encodebin->srcpad != NULL) { + gst_element_remove_pad(GST_ELEMENT(encodebin), encodebin->srcpad); + encodebin->srcpad = NULL; + } + + G_OBJECT_CLASS (parent_class)->dispose (object); + + encodebin->video_sinkpad = NULL; + encodebin->audio_sinkpad = NULL; + encodebin->image_sinkpad = NULL; + encodebin->mux_audio_sinkpad = NULL; + encodebin->mux_video_sinkpad = NULL; + + encodebin->audio_queue = NULL; + encodebin->video_queue = NULL; + encodebin->image_queue = NULL; + + encodebin->audio_encode = NULL; + encodebin->video_encode = NULL; + encodebin->video_encode_queue = NULL; + encodebin->image_encode = NULL; + + encodebin->vcapsfilter = NULL; + encodebin->acapsfilter = NULL; + encodebin->icapsfilter = NULL; + + encodebin->video_toggle = NULL; + encodebin->image_toggle = NULL; + encodebin->color_space = NULL; + encodebin->audio_conv = NULL; + encodebin->audio_sample = NULL; + + if (encodebin->mux && GST_IS_ELEMENT(encodebin->mux)) { + int remain_count= 0; + remain_count = GST_OBJECT_REFCOUNT_VALUE(encodebin->mux); + while (remain_count) { + gst_object_unref(encodebin->mux); + remain_count--; + } + } + + encodebin->mux = NULL; +} + +static void +gst_encode_bin_finalize (GObject * object) +{ + GstEncodeBin *encodebin = GST_ENCODE_BIN (object); + + g_mutex_free (encodebin->mutex); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static GstStateChangeReturn +gst_encode_bin_change_state (GstElement * element, GstStateChange transition) +{ + GstStateChangeReturn ret; + GstEncodeBin *encode_bin; + + encode_bin = GST_ENCODE_BIN (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + gst_encode_bin_link_elements(encode_bin); + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + /* reset time related values */ + encode_bin->paused_time = 0; + encode_bin->total_offset_time = 0; + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + 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_encode_bin_unlink_elements(encode_bin); + break; + default: + break; + } + +// if (ret == GST_STATE_CHANGE_FAILURE) +// goto done; +//done: + return ret; +} + +static void +gst_encode_bin_release_all_pads (GstEncodeBin *encodebin) +{ + gst_element_remove_pad(GST_ELEMENT(encodebin), encodebin->video_sinkpad); + gst_element_remove_pad(GST_ELEMENT(encodebin), encodebin->audio_sinkpad); + gst_element_remove_pad(GST_ELEMENT(encodebin), encodebin->image_sinkpad); +} + +static void +gst_encode_bin_release_pad (GstElement * element, GstPad * pad) +{ + GstEncodeBin *encodebin = GST_ENCODE_BIN (element); + GstPad *muxpad = NULL; + + if(!pad_compare_name(pad, "video")) { +#if 0 + gst_encode_bin_remove_element(encodebin, encodebin->video_queue); + encodebin->video_queue = NULL; + gst_encode_bin_remove_element(encodebin, encodebin->video_toggle); + encodebin->video_toggle = NULL; + gst_encode_bin_remove_element(encodebin, encodebin->color_space); + encodebin->color_space = NULL; + gst_encode_bin_remove_element(encodebin, encodebin->vcapsfilter); + encodebin->vcapsfilter = NULL; + gst_encode_bin_remove_element(encodebin, encodebin->video_encode_queue); + encodebin->video_encode_queue = NULL; + gst_encode_bin_remove_element(encodebin, encodebin->video_encode); + encodebin->video_encode = NULL; + + gst_element_release_request_pad(encodebin->mux, encodebin->mux_video_sinkpad); + encodebin->mux_video_sinkpad = NULL; + + if(encodebin->mux_audio_sinkpad == NULL) { + gst_encode_bin_remove_element(encodebin, encodebin->mux); + encodebin->mux = NULL; + } + else + { + encodebin->mux_audio_sinkpad = NULL; + } +#endif + + if(encodebin->mux_video_sinkpad != NULL) + { + gst_element_release_request_pad(encodebin->mux, encodebin->mux_video_sinkpad); + encodebin->mux_video_sinkpad = NULL; + } + + gst_pad_set_active (pad, FALSE); //?? + gst_element_remove_pad(element, pad); + encodebin->video_sinkpad = NULL; + } else if(!pad_compare_name(pad, "audio")) { +#if 0 + gst_encode_bin_remove_element(encodebin, encodebin->audio_queue); + encodebin->audio_queue = NULL; + gst_encode_bin_remove_element(encodebin, encodebin->audio_sample); + encodebin->audio_sample = NULL; + gst_encode_bin_remove_element(encodebin, encodebin->audio_conv); + encodebin->audio_conv = NULL; + gst_encode_bin_remove_element(encodebin, encodebin->acapsfilter); + encodebin->acapsfilter = NULL; + gst_encode_bin_remove_element(encodebin, encodebin->audio_encode_queue); + encodebin->audio_encode_queue = NULL; + gst_encode_bin_remove_element(encodebin, encodebin->audio_encode); + encodebin->audio_encode = NULL; + + encodebin->mux_audio_sinkpad; + gst_element_release_request_pad(encodebin->mux, encodebin->mux_audio_sinkpad); + muxpad = NULL; + + if(encodebin->mux_video_sinkpad == NULL) { + gst_encode_bin_remove_element(encodebin, encodebin->mux); + encodebin->mux = NULL; + } + else + { + encodebin->mux_video_sinkpad = NULL; + } +#endif + if(encodebin->mux_audio_sinkpad != NULL) + { + gst_element_release_request_pad(encodebin->mux, encodebin->mux_audio_sinkpad); +// gst_object_unref(encodebin->mux_audio_sinkpad); //*** + encodebin->mux_audio_sinkpad = NULL; + } + + gst_pad_set_active (pad, FALSE); //?? + gst_element_remove_pad(element, pad); + encodebin->audio_sinkpad = NULL; + } else { +#if 0 + gst_encode_bin_remove_element(encodebin, encodebin->image_queue); + encodebin->image_queue = NULL; + gst_encode_bin_remove_element(encodebin, encodebin->image_toggle); + encodebin->image_toggle = NULL; + gst_encode_bin_remove_element(encodebin, encodebin->color_space); + encodebin->color_space = NULL; + gst_encode_bin_remove_element(encodebin, encodebin->icapsfilter); + encodebin->icapsfilter = NULL; + gst_encode_bin_remove_element(encodebin, encodebin->image_encode); + encodebin->image_encode = NULL; +#endif + gst_pad_set_active (pad, FALSE); //?? + gst_element_remove_pad(element, pad); + encodebin->image_sinkpad = NULL; + } +} + +static gint +pad_compare_name (GstPad * pad1, const gchar * name) +{ + gint result; + + GST_OBJECT_LOCK (pad1); + result = strcmp (GST_PAD_NAME (pad1), name); + GST_OBJECT_UNLOCK (pad1); + + return result; +} + +static gboolean +gst_encode_bin_add_element_by_name (GstEncodeBin *encodebin, GstEncodeBinElement type, const gchar *name) +{ + switch(type) { + case ENCODEBIN_ELEMENT_VENC: + encodebin->video_encode = gst_element_factory_make (name, "video_encode"); + if(encodebin->video_encode != NULL) { + gst_bin_add(GST_BIN(encodebin), encodebin->video_encode); + g_free(encodebin->venc_name); + encodebin->venc_name = NULL; + } else { + goto element_make_fail; + } + break; + case ENCODEBIN_ELEMENT_AENC: + encodebin->audio_encode = gst_element_factory_make (name, "audio_encode"); + if(encodebin->audio_encode != NULL) { + gst_bin_add(GST_BIN(encodebin), encodebin->audio_encode); + g_free(encodebin->aenc_name); + encodebin->aenc_name = NULL; + } else { + goto element_make_fail; + } + break; + case ENCODEBIN_ELEMENT_IENC: + encodebin->image_encode = gst_element_factory_make (name, "image_encode"); + if(encodebin->image_encode != NULL) { + gst_bin_add(GST_BIN(encodebin), encodebin->image_encode); + g_free(encodebin->ienc_name); + encodebin->ienc_name = NULL; + } else { + goto element_make_fail; + } + break; + case ENCODEBIN_ELEMENT_MUX: + encodebin->mux = gst_element_factory_make (name, "mux"); + if(encodebin->mux != NULL) { + gst_bin_add(GST_BIN(encodebin), encodebin->mux); + g_free(encodebin->mux_name); + encodebin->mux_name = NULL; + } else { + goto element_make_fail; + } + break; + case ENCODEBIN_ELEMENT_VIDEO_CONV: + encodebin->color_space = gst_element_factory_make(name, "video_convert"); + if (encodebin->color_space != NULL) { + gst_bin_add(GST_BIN(encodebin), encodebin->color_space); + g_free(encodebin->vconv_name); + encodebin->vconv_name = NULL; + } else { + goto element_make_fail; + } + break; + default: + GST_WARNING_OBJECT(encodebin, "Invalid element type = %d", type); + break; + } + + return TRUE; + +element_make_fail: + GST_WARNING_OBJECT(encodebin, "no such element factory \"%s\"!", name); + return FALSE; +} + +#if 0 //disable unused function +static gboolean +gst_encode_bin_change_profile(GstEncodeBin *encodebin, gboolean newprofile) +{ + + gst_encode_bin_remove_element(encodebin, encodebin->video_encode); + gst_encode_bin_remove_element(encodebin, encodebin->audio_encode); + gst_encode_bin_remove_element(encodebin, encodebin->image_encode); + gst_encode_bin_remove_element(encodebin, encodebin->mux); + + switch (newprofile) { + case GST_ENCODE_BIN_PROFILE_AV : + encodebin->audio_encode = gst_element_factory_make (encodebin->aenc_name, "audio_encode"); + encodebin->video_encode = gst_element_factory_make (encodebin->venc_name,"video_encode"); + encodebin->mux = gst_element_factory_make (encodebin->mux_name,"mux"); + + gst_bin_add_many (GST_BIN (encodebin), + encodebin->audio_encode, + encodebin->video_encode, + encodebin->mux, + NULL); + break; + case GST_ENCODE_BIN_PROFILE_AUDIO : + encodebin->audio_encode = gst_element_factory_make (encodebin->aenc_name, "audio_encode"); + encodebin->mux = gst_element_factory_make (encodebin->mux_name,"mux"); + + gst_bin_add_many (GST_BIN (encodebin), + encodebin->audio_encode, + encodebin->mux, + NULL); + break; + case GST_ENCODE_BIN_PROFILE_IMAGE : + encodebin->image_encode = gst_element_factory_make (encodebin->ienc_name,"image_encode"); + + gst_bin_add_many (GST_BIN (encodebin), + encodebin->image_encode, + NULL); + break; + default: + GST_WARNING_OBJECT(encodebin, "Invalid profile number = %d", encodebin->profile); + return FALSE; + break; + } + return TRUE; + +} + +static void +gst_encode_bin_replace_element (GstEncodeBin *encodebin, gint type, GstElement * newelement) +{ + if(newelement == NULL) { + GST_ERROR_OBJECT(encodebin, "some elements are null\n"); + return; + } + switch(type) { + case PROP_VIDEO_ENC: + gst_encode_bin_remove_element(encodebin, encodebin->video_encode); + encodebin->video_encode = newelement; + gst_object_ref (encodebin->video_encode); + gst_object_sink (GST_OBJECT_CAST (encodebin->video_encode)); // take ownership ?? + gst_bin_add(GST_BIN(encodebin), encodebin->video_encode); + break; + case PROP_AUDIO_ENC: + gst_encode_bin_remove_element(encodebin, encodebin->audio_encode); + encodebin->audio_encode = newelement; + gst_object_ref (encodebin->audio_encode); + gst_object_sink (GST_OBJECT_CAST (encodebin->audio_encode)); + gst_bin_add(GST_BIN(encodebin), encodebin->audio_encode); + break; + case PROP_IMAGE_ENC: + gst_encode_bin_remove_element(encodebin, encodebin->image_encode); + encodebin->image_encode = newelement; + gst_object_ref (encodebin->image_encode); + gst_object_sink (GST_OBJECT_CAST (encodebin->image_encode)); + gst_bin_add(GST_BIN(encodebin), encodebin->image_encode); + break; + case PROP_MUX: + gst_encode_bin_remove_element(encodebin, encodebin->mux); + encodebin->mux = newelement; + gst_object_ref (encodebin->mux); + gst_object_sink (GST_OBJECT_CAST (encodebin->mux)); + gst_bin_add(GST_BIN(encodebin), encodebin->mux); + break; + default: + GST_WARNING_OBJECT(encodebin, "Invalid type = %d", type); + return; + break; + } +} + +static gboolean +gst_encode_bin_replace_element_by_name(GstEncodeBin *encodebin, GstEncodeBinElement type, const gchar *name) +{ + GstPad *sink1, *sink2, *src, *peersink1, *peersink2, *peersrc; + + switch(type) { + case ENCODEBIN_ELEMENT_VENC: + if(encodebin->video_encode == NULL) { + encodebin->video_encode = gst_element_factory_make (name, "video_encode"); + gst_bin_add(GST_BIN(encodebin), encodebin->video_encode); + } else { + sink1 = gst_element_get_static_pad(encodebin->video_encode, "sink"); + src = gst_element_get_static_pad(encodebin->video_encode, "src"); + if(sink1 != NULL) { + peersink1 = gst_pad_get_peer(sink1); + if(peersink1 != NULL) { + if(!gst_pad_unlink(peersink1, sink1)) { + goto unlink_fail; + } + } + } + + if(src !=NULL) { + peersrc = gst_pad_get_peer(src); + if(peersrc != NULL) { + if(!gst_pad_unlink(src, peersrc)) { + goto unlink_fail; + } + } + } + + if(gst_encode_bin_remove_element(encodebin, encodebin->video_encode)) { + if(encodebin->video_encode = gst_element_factory_make (name, "video_encode") != NULL) { + gst_bin_add(GST_BIN(encodebin), encodebin->video_encode); + if(peersink1 != NULL) { + if(!gst_pad_link(peersink1, gst_element_get_pad(encodebin->video_encode, "sink"))) { + goto link_fail; + } + } + + if(peersrc != NULL) { + if(!gst_pad_link(gst_element_get_pad(encodebin->video_encode, "src"), peersrc)) { + goto link_fail; + } + } + } else { + GST_ERROR_OBJECT(encodebin, "gst_encode_bin_replace_element_by_name() new element[%d] make fail\n", type); + return FALSE; + } + } else { + GST_ERROR_OBJECT(encodebin, "gst_encode_bin_replace_element_by_name() old element[%d] remove fail\n", type); + return FALSE; + } + } + break; + case ENCODEBIN_ELEMENT_AENC: + break; + case ENCODEBIN_ELEMENT_IENC: + break; + case ENCODEBIN_ELEMENT_MUX: + break; + default : + GST_WARNING_OBJECT(encodebin, "Invalid element type = %d", type); + break; + } + gst_object_unref(sink1); + gst_object_unref(sink2); + gst_object_unref(src); + gst_object_unref(peersink1); + gst_object_unref(peersink2); + gst_object_unref(peersrc); + return TRUE; + +unlink_fail: + gst_object_unref(sink1); + gst_object_unref(sink2); + gst_object_unref(src); + gst_object_unref(peersink1); + gst_object_unref(peersink2); + gst_object_unref(peersrc); + GST_ERROR_OBJECT(encodebin, "gst_encode_bin_replace_element_by_name() old element[%d] unlink fail\n", type); + return FALSE; + + +link_fail: + gst_object_unref(sink1); + gst_object_unref(sink2); + gst_object_unref(src); + gst_object_unref(peersink1); + gst_object_unref(peersink2); + gst_object_unref(peersrc); + GST_ERROR_OBJECT(encodebin, "gst_encode_bin_replace_element_by_name() new element[%d] link fail\n", type); + return FALSE; +} + +static gboolean +gst_encode_bin_replace_element_by_object(GstEncodeBin *encodebin, GstEncodeBinElement type, GstElement * element) +{ + GstPad *sink1, *sink2, *src, *peersink1, *peersink2, *peersrc; + + switch(type) + case ENCODEBIN_ELEMENT_VENC: + if(encodebin->video_encode == NULL) { + encodebin->video_encode = element + } + break; + case ENCODEBIN_ELEMENT_AENC: + break; + case ENCODEBIN_ELEMENT_IENC: + break; + case ENCODEBIN_ELEMENT_MUX: + break; + default : + GST_WARNING_OBJECT (encodebin,"Invalid element type = %d", type); + break; +} +#endif //disable unused function + +static gboolean +gst_encode_bin_remove_element (GstEncodeBin *encodebin, GstElement * element) +{ + GstObject *parent; + gchar *ename = NULL; + GST_INFO_OBJECT (encodebin, "gst_encode_bin_remove_element"); + + if (element == NULL) { + GST_INFO_OBJECT (encodebin, "element is already NULL"); + return TRUE; + } + + gst_element_set_state (element, GST_STATE_NULL); + parent = gst_element_get_parent (element); + + if (parent != NULL) { + if(!gst_bin_remove (GST_BIN_CAST (parent), element)) { + gst_object_unref (parent); + ename = gst_element_get_name (element); + GST_ERROR_OBJECT (encodebin, "gst_encode_bin_remove_element() [%s] remove fail", ename); + g_free (ename); + return FALSE; + } else { + gst_object_unref(parent); + } + } else { + gst_object_unref(element); + } + + return TRUE; + } + +static gboolean +gst_encode_bin_link_elements (GstEncodeBin *encodebin) // need to return ???? +{ + GstPad *srcpad = NULL, *sinkpad = NULL; + switch(encodebin->profile) { + case GST_ENCODE_BIN_PROFILE_AV : + if (!gst_caps_is_any(encodebin->vcaps)) { + gchar *caps_str = NULL; + caps_str = gst_caps_to_string(encodebin->vcaps); + if (caps_str) { + GST_INFO_OBJECT(encodebin, "vconv caps [%s]", caps_str); + g_free(caps_str); + caps_str = NULL; + } + + g_object_set(encodebin->vcapsfilter, "caps", encodebin->vcaps, NULL); + } + + if (encodebin->auto_color_space) { + if(encodebin->color_space == NULL) { + encodebin->color_space = gst_element_factory_make (encodebin->vconv_name, "video_convert"); + gst_bin_add (GST_BIN (encodebin), encodebin->color_space); + } + + srcpad = gst_element_get_static_pad(encodebin->video_queue, "src"); + if( encodebin->video_toggle ) + { + sinkpad = gst_element_get_static_pad(encodebin->video_toggle, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + + srcpad = gst_element_get_static_pad(encodebin->video_toggle, "src"); + } + sinkpad = gst_element_get_static_pad(encodebin->color_space, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + + srcpad = gst_element_get_static_pad(encodebin->color_space, "src"); + sinkpad = gst_element_get_static_pad(encodebin->vcapsfilter, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + + srcpad = gst_element_get_static_pad(encodebin->vcapsfilter, "src"); + sinkpad = gst_element_get_static_pad(encodebin->video_encode, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); +#if 0 + if(encodebin->use_venc_queue) + { + if(encodebin->video_encode_queue == NULL) { + encodebin->video_encode_queue = gst_element_factory_make ("queue","video_encode_queue"); + gst_bin_add (GST_BIN (encodebin), encodebin->video_encode_queue); + + ENCODER_QUEUE_SET(encodebin->video_encode_queue, 0, 0, VIDEO_ENC_QUE_TIME); + encodebin->veque_sig_id = g_signal_connect( G_OBJECT(encodebin->video_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); + + } + + srcpad = gst_element_get_static_pad(encodebin->video_encode, "src"); + sinkpad = gst_element_get_static_pad(encodebin->video_encode_queue, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + } +#else + if(encodebin->video_encode_queue) + { + ENCODER_QUEUE_SET(encodebin->video_encode_queue, 0, 0, VIDEO_ENC_QUE_TIME); + encodebin->veque_sig_id = g_signal_connect( G_OBJECT(encodebin->video_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); +#if 0 + g_object_set(G_OBJECT(encodebin->video_queue), + "max-size-bytes", (guint)0, + "max-size-buffers", (guint)1, + "max-size-time", (guint64)0, + NULL); +#endif + srcpad = gst_element_get_static_pad(encodebin->video_encode, "src"); + sinkpad = gst_element_get_static_pad(encodebin->video_encode_queue, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + } +#endif + + } + else { + srcpad = gst_element_get_static_pad(encodebin->video_queue, "src"); + if( encodebin->video_toggle ) + { + sinkpad = gst_element_get_static_pad(encodebin->video_toggle, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + + srcpad = gst_element_get_static_pad(encodebin->video_toggle, "src"); + } + sinkpad = gst_element_get_static_pad(encodebin->vcapsfilter, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + + srcpad = gst_element_get_static_pad(encodebin->vcapsfilter, "src"); + sinkpad = gst_element_get_static_pad(encodebin->video_encode, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + #if 0 + if(encodebin->use_venc_queue) + { + if(encodebin->video_encode_queue == NULL) { + encodebin->video_encode_queue = gst_element_factory_make ("queue","video_encode_queue"); + gst_bin_add (GST_BIN (encodebin), encodebin->video_encode_queue); + + ENCODER_QUEUE_SET(encodebin->video_encode_queue, 0, 0, VIDEO_ENC_QUE_TIME); + encodebin->veque_sig_id = g_signal_connect( G_OBJECT(encodebin->video_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); + } + + srcpad = gst_element_get_static_pad(encodebin->video_encode, "src"); + sinkpad = gst_element_get_static_pad(encodebin->video_encode_queue, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + + } +#else + if(encodebin->video_encode_queue) + { + ENCODER_QUEUE_SET(encodebin->video_encode_queue, 0, 0, VIDEO_ENC_QUE_TIME); + encodebin->veque_sig_id = g_signal_connect( G_OBJECT(encodebin->video_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); +#if 0 + g_object_set(G_OBJECT(encodebin->video_queue), + "max-size-bytes", (guint)0, + "max-size-buffers", (guint)1, + "max-size-time", (guint64)0, + NULL); +#endif + + srcpad = gst_element_get_static_pad(encodebin->video_encode, "src"); + sinkpad = gst_element_get_static_pad(encodebin->video_encode_queue, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + } +#endif + + } + +// gst_element_get_request_pad (encodebin->mux, "video_%d"); +#if 0 + if(encodebin->use_venc_queue) + { + srcpad = gst_element_get_static_pad(encodebin->video_encode_queue, "src"); + sinkpad = encodebin->mux_video_sinkpad = gst_encode_bin_get_mux_sink_pad(encodebin->mux, ENCODEBIN_MUX_VIDEO_SINK); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + } +#else + if(encodebin->video_encode_queue) + { + srcpad = gst_element_get_static_pad(encodebin->video_encode_queue, "src"); + sinkpad = encodebin->mux_video_sinkpad = gst_encode_bin_get_mux_sink_pad(encodebin->mux, ENCODEBIN_MUX_VIDEO_SINK); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + } +#endif + else + { + srcpad = gst_element_get_static_pad(encodebin->video_encode, "src"); + sinkpad = encodebin->mux_video_sinkpad = gst_encode_bin_get_mux_sink_pad(encodebin->mux, ENCODEBIN_MUX_VIDEO_SINK); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, video_link_fail); + } + + srcpad = gst_element_get_static_pad(encodebin->mux, "src"); + if(gst_ghost_pad_get_target(GST_GHOST_PAD (encodebin->srcpad)) != srcpad) + gst_ghost_pad_set_target(GST_GHOST_PAD (encodebin->srcpad), srcpad); + gst_object_unref(srcpad); + srcpad = NULL; + + /* For pause/resume control */ +// encodebin->vsink_probeid = gst_pad_add_data_probe (gst_element_get_static_pad (encodebin->video_queue, "sink"), + sinkpad = gst_element_get_static_pad (encodebin->video_queue, "sink"); + encodebin->vsink_probeid = gst_pad_add_probe(sinkpad, GST_PAD_PROBE_TYPE_BUFFER, (GstPadProbeCallback)gst_encode_bin_video_probe, encodebin, NULL); + gst_object_unref(sinkpad); + sinkpad = NULL; + + if(encodebin->high_speed_fps > DEFAULT_PROP_HIGH_SPEED) + { +// encodebin->vsink_hs_probeid = gst_pad_add_data_probe (gst_element_get_static_pad (encodebin->video_encode, "sink"), + sinkpad = gst_element_get_static_pad (encodebin->video_encode, "sink"); + encodebin->vsink_hs_probeid = gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BUFFER, (GstPadProbeCallback)gst_encode_bin_video_probe_hs, encodebin, NULL); + gst_object_unref(sinkpad); + sinkpad = NULL; + } + + if(encodebin->audio_queue == NULL) + { + GST_WARNING_OBJECT(encodebin, "Audio pad isn't requested, recording video only mode"); + break; + } + case GST_ENCODE_BIN_PROFILE_AUDIO : + if(!gst_caps_is_any(encodebin->acaps)) + { + g_object_set(encodebin->acapsfilter, "caps", encodebin->acaps, NULL); + } + if (encodebin->auto_audio_convert ||encodebin->auto_audio_resample) { + if (!encodebin->auto_audio_convert) { + if(encodebin->audio_sample == NULL) { + encodebin->audio_sample = gst_element_factory_make ("audioresample","audio_sample"); + gst_bin_add (GST_BIN (encodebin), encodebin->audio_sample); + } + srcpad = gst_element_get_static_pad(encodebin->audio_queue, "src"); + sinkpad = gst_element_get_static_pad(encodebin->audio_sample, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + + srcpad = gst_element_get_static_pad(encodebin->audio_sample, "src"); + sinkpad = gst_element_get_static_pad(encodebin->acapsfilter, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + + srcpad = gst_element_get_static_pad(encodebin->acapsfilter, "src"); + sinkpad = gst_element_get_static_pad(encodebin->audio_encode, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); +#if 0 + if(encodebin->use_aenc_queue) + { + if(encodebin->audio_encode_queue == NULL) { + encodebin->audio_encode_queue = gst_element_factory_make ("queue","audio_encode_queue"); + gst_bin_add (GST_BIN (encodebin), encodebin->audio_encode_queue); + + ENCODER_QUEUE_SET(encodebin->audio_encode_queue, 0, 0, AUDIO_ENC_QUE_TIME); + encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); + } + + srcpad = gst_element_get_static_pad(encodebin->audio_encode, "src"); + sinkpad = gst_element_get_static_pad(encodebin->audio_encode_queue, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + } +#else + if(encodebin->audio_encode_queue) + { + + ENCODER_QUEUE_SET(encodebin->audio_encode_queue, 0, 0, AUDIO_ENC_QUE_TIME); + encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); + + srcpad = gst_element_get_static_pad(encodebin->audio_encode, "src"); + sinkpad = gst_element_get_static_pad(encodebin->audio_encode_queue, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + } +#endif + + } else if (!encodebin->auto_audio_resample) { + if (encodebin->audio_conv == NULL) { + encodebin->audio_conv = gst_element_factory_make ("audioconvert","audio_conv"); + gst_bin_add (GST_BIN (encodebin), encodebin->audio_conv); + } + + srcpad = gst_element_get_static_pad(encodebin->audio_queue, "src"); + sinkpad = gst_element_get_static_pad(encodebin->audio_conv, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + + srcpad = gst_element_get_static_pad(encodebin->audio_conv, "src"); + sinkpad = gst_element_get_static_pad(encodebin->acapsfilter, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + + srcpad = gst_element_get_static_pad(encodebin->acapsfilter, "src"); + sinkpad = gst_element_get_static_pad(encodebin->audio_encode, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); +#if 0 + if(encodebin->use_aenc_queue) + { + if(encodebin->audio_encode_queue == NULL) { + encodebin->audio_encode_queue = gst_element_factory_make ("queue","audio_encode_queue"); + gst_bin_add (GST_BIN (encodebin), encodebin->audio_encode_queue); + + ENCODER_QUEUE_SET(encodebin->audio_encode_queue, 0, 0, AUDIO_ENC_QUE_TIME); + encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); + } + + srcpad = gst_element_get_static_pad(encodebin->audio_encode, "src"); + sinkpad = gst_element_get_static_pad(encodebin->audio_encode_queue, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + + } +#else + if(encodebin->audio_encode_queue) + { + + ENCODER_QUEUE_SET(encodebin->audio_encode_queue, 0, 0, AUDIO_ENC_QUE_TIME); + encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); + + srcpad = gst_element_get_static_pad(encodebin->audio_encode, "src"); + sinkpad = gst_element_get_static_pad(encodebin->audio_encode_queue, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + } +#endif + + } else { + if(encodebin->audio_sample == NULL) { + encodebin->audio_sample = gst_element_factory_make ("audioresample","audio_sample"); + gst_bin_add (GST_BIN (encodebin), encodebin->audio_sample); + } + if (encodebin->audio_conv == NULL) { + encodebin->audio_conv = gst_element_factory_make ("audioconvert","audio_conv"); + gst_bin_add (GST_BIN (encodebin), encodebin->audio_conv); + } + + srcpad = gst_element_get_static_pad(encodebin->audio_queue, "src"); + sinkpad = gst_element_get_static_pad(encodebin->audio_conv, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + + srcpad = gst_element_get_static_pad(encodebin->audio_conv, "src"); + sinkpad = gst_element_get_static_pad(encodebin->audio_sample, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + + srcpad = gst_element_get_static_pad(encodebin->audio_sample, "src"); + sinkpad = gst_element_get_static_pad(encodebin->acapsfilter, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + + srcpad = gst_element_get_static_pad(encodebin->acapsfilter, "src"); + sinkpad = gst_element_get_static_pad(encodebin->audio_encode, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); +#if 0 + if(encodebin->use_aenc_queue) + { + if(encodebin->audio_encode_queue == NULL) { + encodebin->audio_encode_queue = gst_element_factory_make ("queue","audio_encode_queue"); + gst_bin_add (GST_BIN (encodebin), encodebin->audio_encode_queue); + + ENCODER_QUEUE_SET(encodebin->audio_encode_queue, 0, 0, AUDIO_ENC_QUE_TIME); + encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); + } + + srcpad = gst_element_get_static_pad(encodebin->audio_encode, "src"); + sinkpad = gst_element_get_static_pad(encodebin->audio_encode_queue, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + + } +#else + if(encodebin->audio_encode_queue) + { + + ENCODER_QUEUE_SET(encodebin->audio_encode_queue, 0, 0, AUDIO_ENC_QUE_TIME); + encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); + + srcpad = gst_element_get_static_pad(encodebin->audio_encode, "src"); + sinkpad = gst_element_get_static_pad(encodebin->audio_encode_queue, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + } +#endif + + } + }else { + + srcpad = gst_element_get_static_pad(encodebin->audio_queue, "src"); + sinkpad = gst_element_get_static_pad(encodebin->acapsfilter, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + + srcpad = gst_element_get_static_pad(encodebin->acapsfilter, "src"); + sinkpad = gst_element_get_static_pad(encodebin->audio_encode, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); +#if 0 + if(encodebin->use_aenc_queue) + { + if(encodebin->audio_encode_queue == NULL) { + encodebin->audio_encode_queue = gst_element_factory_make ("queue","audio_encode_queue"); + gst_bin_add (GST_BIN (encodebin), encodebin->audio_encode_queue); + + ENCODER_QUEUE_SET(encodebin->audio_encode_queue, 0, 0, AUDIO_ENC_QUE_TIME); + encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); + } + + srcpad = gst_element_get_static_pad(encodebin->audio_encode, "src"); + sinkpad = gst_element_get_static_pad(encodebin->audio_encode_queue, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + } +#else + if(encodebin->audio_encode_queue) + { + + ENCODER_QUEUE_SET(encodebin->audio_encode_queue, 0, 0, AUDIO_ENC_QUE_TIME); + encodebin->aeque_sig_id = g_signal_connect( G_OBJECT(encodebin->audio_encode_queue), "overrun", + G_CALLBACK(queue_overun_cb), encodebin); + + srcpad = gst_element_get_static_pad(encodebin->audio_encode, "src"); + sinkpad = gst_element_get_static_pad(encodebin->audio_encode_queue, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + } +#endif + + } +#if 0 + if(encodebin->use_aenc_queue) + { + srcpad = gst_element_get_static_pad(encodebin->audio_encode_queue, "src"); + sinkpad = encodebin->mux_audio_sinkpad = gst_encode_bin_get_mux_sink_pad(encodebin->mux, ENCODEBIN_MUX_AUDIO_SINK); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + + } +#else + + if(encodebin->audio_encode_queue) + { + srcpad = gst_element_get_static_pad(encodebin->audio_encode_queue, "src"); + sinkpad = encodebin->mux_audio_sinkpad = gst_encode_bin_get_mux_sink_pad(encodebin->mux, ENCODEBIN_MUX_AUDIO_SINK); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + + } +#endif + else + { + srcpad = gst_element_get_static_pad(encodebin->audio_encode, "src"); + sinkpad = encodebin->mux_audio_sinkpad = gst_encode_bin_get_mux_sink_pad(encodebin->mux, ENCODEBIN_MUX_AUDIO_SINK); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, audio_link_fail); + + } + + srcpad = gst_element_get_static_pad(encodebin->mux, "src"); + if(gst_ghost_pad_get_target(GST_GHOST_PAD (encodebin->srcpad)) != srcpad) + gst_ghost_pad_set_target(GST_GHOST_PAD (encodebin->srcpad), srcpad); + gst_object_unref(srcpad); + srcpad = NULL; + + /* For pause/resume control */ + sinkpad = gst_element_get_static_pad (encodebin->audio_queue, "sink"); + encodebin->asink_probeid = gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_BUFFER, (GstPadProbeCallback)gst_encode_bin_audio_probe, encodebin, NULL); + gst_object_unref(sinkpad); + sinkpad = NULL; + + break; + case GST_ENCODE_BIN_PROFILE_IMAGE : + if(!gst_caps_is_any(encodebin->icaps)) + { + g_object_set(encodebin->icapsfilter, "caps", encodebin->icaps, NULL); + } + + if (encodebin->auto_color_space) { + if(encodebin->color_space == NULL) { + encodebin->color_space = gst_element_factory_make ("videoconvert","color_space"); + gst_bin_add (GST_BIN (encodebin), encodebin->color_space); + } + + srcpad = gst_element_get_static_pad(encodebin->image_queue, "src"); + sinkpad = gst_element_get_static_pad(encodebin->image_toggle, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, image_link_fail); + + srcpad = gst_element_get_static_pad(encodebin->image_toggle, "src"); + sinkpad = gst_element_get_static_pad(encodebin->color_space, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, image_link_fail); + + srcpad = gst_element_get_static_pad(encodebin->color_space, "src"); + sinkpad = gst_element_get_static_pad(encodebin->icapsfilter, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, image_link_fail); + + srcpad = gst_element_get_static_pad(encodebin->icapsfilter, "src"); + sinkpad = gst_element_get_static_pad(encodebin->image_encode, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, image_link_fail); + + } + else { + + srcpad = gst_element_get_static_pad(encodebin->image_queue, "src"); + sinkpad = gst_element_get_static_pad(encodebin->image_toggle, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, image_link_fail); + + srcpad = gst_element_get_static_pad(encodebin->image_toggle, "src"); + sinkpad = gst_element_get_static_pad(encodebin->icapsfilter, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, image_link_fail); + + srcpad = gst_element_get_static_pad(encodebin->icapsfilter, "src"); + sinkpad = gst_element_get_static_pad(encodebin->image_encode, "sink"); + _GST_PAD_LINK_UNREF(srcpad, sinkpad, image_link_fail); + + } + srcpad = gst_element_get_static_pad (encodebin->image_encode, "src"); + if(gst_ghost_pad_get_target(GST_GHOST_PAD (encodebin->srcpad)) != srcpad) + gst_ghost_pad_set_target(GST_GHOST_PAD (encodebin->srcpad), srcpad); + gst_object_unref(srcpad); + srcpad = NULL; + break; + default: + GST_WARNING_OBJECT(encodebin, "Invalid profile number = %d", encodebin->profile); + return FALSE; + break; + } +// gst_pad_set_active(encodebin->srcpad, TRUE); + return TRUE; + +video_link_fail: + // remove elements + gst_encode_bin_remove_element(encodebin, encodebin->color_space); + GST_WARNING_OBJECT(encodebin, "encodebin link video elements fail"); + return FALSE; + +audio_link_fail: + // remove element + gst_encode_bin_remove_element(encodebin, encodebin->audio_conv); + gst_encode_bin_remove_element(encodebin, encodebin->audio_sample); + GST_WARNING_OBJECT(encodebin, "encodebin link audio elements fail"); + return FALSE; + +image_link_fail: + // remove element + gst_encode_bin_remove_element(encodebin, encodebin->color_space); + GST_WARNING_OBJECT(encodebin, "encodebin link image elements fail"); + return FALSE; + + +} + +static gboolean +gst_encode_bin_unlink_elements (GstEncodeBin *encodebin) +{ + GstPad *pad = NULL, *muxpad = NULL; + + switch(encodebin->profile) { + case GST_ENCODE_BIN_PROFILE_AV : + if (encodebin->auto_color_space) { + if (encodebin->video_toggle) { + gst_element_unlink_many( + encodebin->video_queue, + encodebin->video_toggle, + encodebin->color_space, + encodebin->vcapsfilter, + encodebin->video_encode, + //encodebin->video_encode_queue, + NULL); + } else { + gst_element_unlink_many( + encodebin->video_queue, + encodebin->color_space, + encodebin->vcapsfilter, + encodebin->video_encode, + //encodebin->video_encode_queue, + NULL); + } + } else { + if (encodebin->video_toggle) { + gst_element_unlink_many( + encodebin->video_queue, + encodebin->video_toggle, + encodebin->vcapsfilter, + encodebin->video_encode, + //encodebin->video_encode_queue, + NULL); + } else { + gst_element_unlink_many( + encodebin->video_queue, + encodebin->vcapsfilter, + encodebin->video_encode, + //encodebin->video_encode_queue, + NULL); + } + } + + if(encodebin->mux_video_sinkpad != NULL) + { +#if 0 + if(encodebin->use_venc_queue) + { + gst_element_unlink(encodebin->video_encode, encodebin->video_encode_queue); + + pad = gst_element_get_static_pad (encodebin->video_encode_queue, "src"); + gst_pad_unlink(pad, muxpad); + gst_object_unref(pad); + pad = NULL; + + if ( g_signal_handler_is_connected ( encodebin->video_encode_queue, encodebin->veque_sig_id) ) + { + g_signal_handler_disconnect ( encodebin->video_encode_queue, encodebin->veque_sig_id ); + } + } +#else + if(encodebin->video_encode_queue) + { + gst_element_unlink(encodebin->video_encode, encodebin->video_encode_queue); + + pad = gst_element_get_static_pad (encodebin->video_encode_queue, "src"); + gst_pad_unlink(pad, encodebin->mux_video_sinkpad); + gst_object_unref(pad); + pad = NULL; + + if ( g_signal_handler_is_connected ( encodebin->video_encode_queue, encodebin->veque_sig_id) ) + { + g_signal_handler_disconnect ( encodebin->video_encode_queue, encodebin->veque_sig_id ); + } + } +#endif + else + { + pad = gst_element_get_static_pad (encodebin->video_encode, "src"); + gst_pad_unlink(pad, encodebin->mux_video_sinkpad); + gst_object_unref(pad); + pad = NULL; + } + + gst_element_release_request_pad(encodebin->mux, encodebin->mux_video_sinkpad); +// gst_object_unref(encodebin->mux_video_sinkpad); //*** + encodebin->mux_video_sinkpad = NULL; + } + + if(encodebin->vsink_probeid) + { + pad = gst_element_get_static_pad (encodebin->video_queue, "sink"); + gst_pad_remove_probe(pad, encodebin->vsink_probeid); + encodebin->vsink_probeid = 0; + gst_object_unref(pad); + pad = NULL; + } + + + if(encodebin->vsink_hs_probeid) + { + pad = gst_element_get_static_pad (encodebin->video_encode, "sink"); + gst_pad_remove_probe(pad, encodebin->vsink_hs_probeid); + encodebin->vsink_hs_probeid = 0; + gst_object_unref(pad); + pad = NULL; + } + + if(encodebin->audio_queue == NULL) + { + break; + } + case GST_ENCODE_BIN_PROFILE_AUDIO : + if (encodebin->auto_audio_convert ||encodebin->auto_audio_resample) { + if (!encodebin->auto_audio_convert) { + gst_element_unlink_many ( + encodebin->audio_queue, + encodebin->audio_sample, + encodebin->acapsfilter, + encodebin->audio_encode, + NULL); + } else if (!encodebin->auto_audio_resample) { + gst_element_unlink_many ( + encodebin->audio_queue, + encodebin->audio_conv, + encodebin->acapsfilter, + encodebin->audio_encode, + NULL); + } else { + gst_element_unlink_many ( + encodebin->audio_queue, + encodebin->audio_conv, + encodebin->audio_sample, + encodebin->acapsfilter, + encodebin->audio_encode, + NULL); + } + } + else { + gst_element_unlink_many ( + encodebin->audio_queue, + encodebin->acapsfilter, + encodebin->audio_encode, + NULL); + } + + if(encodebin->mux_audio_sinkpad != NULL) + { +#if 0 + if(encodebin->use_aenc_queue) + { + gst_element_unlink(encodebin->audio_encode, encodebin->audio_encode_queue); + + pad = gst_element_get_static_pad (encodebin->audio_encode_queue, "src"); + gst_pad_unlink(pad, muxpad); + gst_object_unref(pad); + pad = NULL; + + if ( g_signal_handler_is_connected ( encodebin->audio_encode_queue, encodebin->veque_sig_id) ) + { + g_signal_handler_disconnect ( encodebin->audio_encode_queue, encodebin->veque_sig_id ); + } + } +#else + if(encodebin->audio_encode_queue) + { + gst_element_unlink(encodebin->audio_encode, encodebin->audio_encode_queue); + + pad = gst_element_get_static_pad (encodebin->audio_encode_queue, "src"); + gst_pad_unlink(pad, encodebin->mux_audio_sinkpad); + gst_object_unref(pad); + pad = NULL; + + if ( g_signal_handler_is_connected ( encodebin->audio_encode_queue, encodebin->veque_sig_id) ) + { + g_signal_handler_disconnect ( encodebin->audio_encode_queue, encodebin->veque_sig_id ); + } + } +#endif + else + { + pad = gst_element_get_static_pad (encodebin->audio_encode, "src"); + gst_pad_unlink(pad, encodebin->mux_audio_sinkpad); + gst_object_unref(pad); + pad = NULL; + } + + gst_element_release_request_pad(encodebin->mux, encodebin->mux_audio_sinkpad); +// gst_object_unref(encodebin->mux_audio_sinkpad); //*** + encodebin->mux_audio_sinkpad = NULL; + } + + if(encodebin->asink_probeid) + { + pad = gst_element_get_static_pad (encodebin->audio_queue, "sink"); + gst_pad_remove_probe(pad, encodebin->asink_probeid); + encodebin->asink_probeid =0; + gst_object_unref(pad); + pad = NULL; + } + + break; + case GST_ENCODE_BIN_PROFILE_IMAGE : + if (encodebin->auto_color_space) { + gst_element_unlink_many ( + encodebin->image_queue, + encodebin->image_toggle, + encodebin->color_space, + encodebin->icapsfilter, + encodebin->image_encode, + NULL); + } + else { + gst_element_unlink_many ( + encodebin->image_queue, + encodebin->image_toggle, + encodebin->icapsfilter, + encodebin->image_encode, + NULL); + } + break; + default: + GST_WARNING_OBJECT(encodebin, "Invalid profile number = %d", encodebin->profile); + return FALSE; + break; + } + // gst_pad_set_active(encodebin->srcpad, TRUE); + return TRUE; + +} + +static gboolean +gst_encode_bin_init_video_elements (GstElement *element, gpointer user_data) +{ + GstEncodeBin *encodebin = GST_ENCODE_BIN (element); + + if(encodebin->profile != GST_ENCODE_BIN_PROFILE_AV) + return FALSE; + + if(encodebin->video_queue == NULL) { + encodebin->video_queue = gst_element_factory_make ("queue","video_queue"); + gst_bin_add (GST_BIN (element), encodebin->video_queue); + } + + if( encodebin->use_video_toggle ) + { + if( encodebin->video_toggle == NULL ) + { + encodebin->video_toggle = gst_element_factory_make ("toggle","video_toggle"); + gst_bin_add (GST_BIN (element), encodebin->video_toggle); + } + GST_INFO_OBJECT( encodebin, "Video toggle is Enabled" ); + } + else + { + GST_INFO_OBJECT( encodebin, "Video toggle is Disabled" ); + } + + if(encodebin->vcapsfilter == NULL) { + encodebin->vcapsfilter = gst_element_factory_make ("capsfilter","vcapsfilter"); + gst_bin_add (GST_BIN (element), encodebin->vcapsfilter); + } +#if 0 + encodebin->vcaps = gst_caps_new_simple("video/x-raw", + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'), + "width", G_TYPE_INT, 320, + "height", G_TYPE_INT, 240, + "framerate", GST_TYPE_FRACTION, 30, 1, + NULL); + +#endif + if(encodebin->video_encode == NULL) { + encodebin->video_encode = gst_element_factory_make (encodebin->venc_name, "video_encode"); + gst_bin_add (GST_BIN (element), encodebin->video_encode); + } + +#if 0 + if(encodebin->video_encode_queue == NULL) { + encodebin->video_encode_queue = gst_element_factory_make ("queue", "video_encode_queue"); + gst_bin_add (GST_BIN (element), encodebin->video_encode_queue); + } + + g_object_set(G_OBJECT(encodebin->video_encode_queue), "max-size-bytes", (unsigned int)0, NULL); +#endif + + if(encodebin->mux == NULL) { + encodebin->mux = gst_element_factory_make (encodebin->mux_name, "mux"); + gst_bin_add (GST_BIN (element), encodebin->mux); + } + + if (!encodebin->video_encode +// || !encodebin->video_encode_queue + || !encodebin->mux + || !encodebin->video_queue + || !encodebin->vcapsfilter + || !encodebin->srcpad ) + { + GST_ERROR_OBJECT(encodebin, "Faild create element \n"); + return FALSE; + } + + if( encodebin->use_video_toggle && !encodebin->video_toggle ) + { + GST_ERROR_OBJECT(encodebin, "Faild create video toggle element \n"); + return FALSE; + } + +#if 0 + if (encodebin->auto_color_space && (encodebin->color_space == NULL)) { + encodebin->color_space = gst_element_factory_make ("videoconvert","color_space"); + gst_bin_add (GST_BIN (element), encodebin->color_space); + } +#endif + return TRUE; +} + +static gboolean +gst_encode_bin_init_audio_elements (GstElement *element, gpointer user_data) +{ + GstEncodeBin *encodebin = GST_ENCODE_BIN (element); + + if(encodebin->profile > GST_ENCODE_BIN_PROFILE_AUDIO) + return FALSE; + + if(encodebin->audio_queue == NULL) { + encodebin->audio_queue = gst_element_factory_make ("queue","audio_queue"); + gst_bin_add (GST_BIN (element), encodebin->audio_queue); + } + + if(encodebin->acapsfilter == NULL) { + encodebin->acapsfilter = gst_element_factory_make ("capsfilter","acapsfilter"); + gst_bin_add (GST_BIN (element), encodebin->acapsfilter); + } +#if 0 +encodebin->acaps = gst_caps_new_simple("audio/x-raw", + "rate", G_TYPE_INT, 8000, + "channels", G_TYPE_INT, 2, + "depth", G_TYPE_INT, 16, + NULL); +#endif + + if(encodebin->audio_encode == NULL) { + encodebin->audio_encode = gst_element_factory_make (encodebin->aenc_name, "audio_encode"); + gst_bin_add (GST_BIN (element), encodebin->audio_encode); + } + + if(encodebin->mux == NULL) { + encodebin->mux = gst_element_factory_make (encodebin->mux_name, "mux"); + gst_bin_add (GST_BIN (element), encodebin->mux); + } + + if (!encodebin->audio_encode + || !encodebin->audio_queue + || !encodebin->mux + || !encodebin->acapsfilter + || !encodebin->srcpad ) + { + GST_ERROR_OBJECT(encodebin, "Faild create element \n"); + return FALSE; + } +#if 0 + if (encodebin->auto_audio_convert && (encodebin->audio_conv == NULL)) { + encodebin->audio_conv = gst_element_factory_make ("audioconvert","audio_conv"); + gst_bin_add (GST_BIN (element), encodebin->audio_conv); + } + + if (encodebin->auto_audio_resample && (encodebin->audio_sample == NULL)) { + encodebin->audio_sample = gst_element_factory_make ("audioresample","audio_sample"); + gst_bin_add (GST_BIN (element), encodebin->audio_sample); + } +#endif + return TRUE; +} + + +static gboolean +gst_encode_bin_init_image_elements (GstElement *element, gpointer user_data) +{ + GstEncodeBin *encodebin = GST_ENCODE_BIN (element); + + if(encodebin->profile < GST_ENCODE_BIN_PROFILE_IMAGE) + return FALSE; + + if(encodebin->image_queue == NULL) { + encodebin->image_queue = gst_element_factory_make ("queue","image_queue"); + gst_bin_add (GST_BIN (element), encodebin->image_queue); + } + + if(encodebin->image_toggle == NULL) { + encodebin->image_toggle = gst_element_factory_make ("toggle","image_toggle"); + gst_bin_add (GST_BIN (element), encodebin->image_toggle); + } + + if(encodebin->icapsfilter == NULL) { + encodebin->icapsfilter = gst_element_factory_make ("capsfilter","icapsfilter"); + gst_bin_add (GST_BIN (element), encodebin->icapsfilter); + } + + if(encodebin->image_encode == NULL) { + encodebin->image_encode = gst_element_factory_make (encodebin->ienc_name, "image_encode"); + gst_bin_add (GST_BIN (element), encodebin->image_encode); + } + + if (!encodebin->image_encode + || !encodebin->image_queue + || !encodebin->image_toggle + || !encodebin->icapsfilter + || !encodebin->srcpad ) + { + GST_ERROR_OBJECT(encodebin, "Faild create element \n"); + return FALSE; + } +#if 0 + if (encodebin->auto_color_space && (encodebin->color_space == NULL)) { + encodebin->color_space = gst_element_factory_make ("videoconvert","color_space"); + gst_bin_add (GST_BIN (element), encodebin->color_space); + } +#endif + return TRUE; +} + +static gboolean gst_encode_bin_block(GstEncodeBin *encodebin, gboolean value) +{ + + if(value) { //block stream + switch(encodebin->profile) { + case GST_ENCODE_BIN_PROFILE_AV: + if(encodebin->audio_queue == NULL && encodebin->video_queue == NULL) { + goto block_fail; + } else { + if(g_object_class_find_property(G_OBJECT_GET_CLASS(GST_OBJECT(encodebin->video_queue)), + "empty-buffers") == NULL) { + GST_ERROR_OBJECT(encodebin, "The queue element doesn't support 'empty-buffers' property"); + goto block_fail; + } + if( encodebin->video_toggle ) + { + g_object_set(encodebin->video_toggle, "block-data", TRUE , NULL); + GST_INFO_OBJECT( encodebin, "video_toggle block-data TRUE" ); + } + + g_object_set(encodebin->video_queue, "empty-buffers", TRUE , NULL); + GST_INFO_OBJECT( encodebin, "video_queue empty-buffers TRUE" ); + if(encodebin->audio_queue != NULL) + { + g_object_set(encodebin->audio_queue, "empty-buffers", TRUE , NULL); + GST_INFO_OBJECT( encodebin, "audio_queue empty-buffers TRUE" ); + } + } + break; + case GST_ENCODE_BIN_PROFILE_AUDIO: + if(encodebin->audio_queue == NULL) { + goto block_fail; + } else { + if(g_object_class_find_property(G_OBJECT_GET_CLASS(GST_OBJECT(encodebin->audio_queue)), + "empty-buffers") == NULL) { + GST_ERROR_OBJECT(encodebin, "The queue element doesn't support 'empty-buffers' property"); + goto block_fail; + } + g_object_set(encodebin->audio_queue, "empty-buffers", TRUE , NULL); + GST_INFO_OBJECT( encodebin, "audio_queue empty-buffers TRUE" ); + } + break; + case GST_ENCODE_BIN_PROFILE_IMAGE: + if(encodebin->image_toggle == NULL) { + goto block_fail; + } else { + g_object_set(encodebin->image_toggle, "block_data", TRUE, NULL); + GST_INFO_OBJECT( encodebin, "image_toggle block_data TRUE" ); + } + break; + default: + GST_WARNING_OBJECT (encodebin,"Invalid profile number = %d", encodebin->profile); + goto block_fail; + break; + } + } else { //release blocked-stream + switch(encodebin->profile) { + case GST_ENCODE_BIN_PROFILE_AV: + if(encodebin->audio_queue == NULL && encodebin->video_queue == NULL) { + goto unblock_fail; + } else { + if(g_object_class_find_property(G_OBJECT_GET_CLASS(GST_OBJECT(encodebin->video_queue)), + "empty-buffers") == NULL) { + GST_ERROR_OBJECT(encodebin, "The queue element doesn't support 'empty-buffers' property"); + goto unblock_fail; + } + if( encodebin->video_toggle ) + { + g_object_set(encodebin->video_toggle, "block-data", FALSE , NULL); + GST_INFO_OBJECT( encodebin, "video_toggle block-data FALSE" ); + } + + if(encodebin->audio_queue != NULL) + { + g_object_set(encodebin->audio_queue, "empty-buffers", FALSE , NULL); + GST_INFO_OBJECT( encodebin, "audio_queue empty-buffers FALSE" ); + } + g_object_set(encodebin->video_queue, "empty-buffers", FALSE , NULL); + GST_INFO_OBJECT( encodebin, "video_queue empty-buffers FALSE" ); + } + break; + case GST_ENCODE_BIN_PROFILE_AUDIO: + if(encodebin->audio_queue == NULL) { + goto unblock_fail; + } else { + if(g_object_class_find_property(G_OBJECT_GET_CLASS(GST_OBJECT(encodebin->audio_queue)), + "empty-buffers") == NULL) { + GST_ERROR_OBJECT(encodebin, "The queue element doesn't support 'empty-buffers' property"); + goto unblock_fail; + } + g_object_set(encodebin->audio_queue, "empty-buffers", FALSE , NULL); + GST_INFO_OBJECT( encodebin, "audio_queue empty-buffers FALSE" ); + } + break; + case GST_ENCODE_BIN_PROFILE_IMAGE: + if(encodebin->image_toggle == NULL) { + goto unblock_fail; + } else { + g_object_set(encodebin->image_toggle, "block_data", FALSE, NULL); + GST_INFO_OBJECT( encodebin, "image_toggle block_data FALSE" ); + } + break; + default: + GST_WARNING_OBJECT (encodebin,"Invalid profile number = %d", encodebin->profile); + goto unblock_fail; + break; + } + } + encodebin->block = value; + return TRUE; + +block_fail: + GST_ERROR_OBJECT(encodebin, "encodebin block failed"); + return FALSE; + +unblock_fail: + GST_ERROR_OBJECT(encodebin, "encodebin unblock failed"); + return FALSE; +} + +static gboolean gst_encode_bin_pause(GstEncodeBin *encodebin, gboolean value) +{ + GstClock *clock = NULL; + + if(value) { + /* pause stream*/ + //Block src of encode bin + if (!gst_encode_bin_block(encodebin, TRUE)) + { + GST_WARNING_OBJECT (encodebin, "Fail to block Encodebin."); + goto pause_fail; + } + + if (encodebin->paused_time == 0) + { + //get steam time + if (clock = GST_ELEMENT_CLOCK(encodebin)) //before PLAYING, this would be NULL. Need to check. + { + GstClockTime current_time, base_time; + + current_time = gst_clock_get_time(clock); + base_time = gst_element_get_base_time(GST_ELEMENT(encodebin)); + + encodebin->paused_time = current_time - base_time; + + GST_INFO_OBJECT (encodebin, "Encodebin is in running-pause at [%"GST_TIME_FORMAT"]." + , GST_TIME_ARGS(encodebin->paused_time)); + } + else + { + encodebin->paused_time = 0; + encodebin->total_offset_time = 0; + + GST_WARNING_OBJECT (encodebin, "There is no clock in Encodebin."); + } + } +#if 0 //def GST_ENCODE_BIN_SIGNAL_ENABLE + g_signal_emit (G_OBJECT (encodebin), gst_encode_bin_signals[SIGNAL_STREAM_PAUSE], 0, TRUE); +#endif + } + else { + /* release paused-stream*/ + if (encodebin->paused_time != 0) + { + if (clock = GST_ELEMENT_CLOCK(encodebin)) + { + GstClockTime current_time, base_time; + GstClockTime paused_gap; + + current_time = gst_clock_get_time(clock); + base_time = gst_element_get_base_time(GST_ELEMENT(encodebin)); + paused_gap = current_time - base_time - encodebin->paused_time; + + encodebin->total_offset_time += paused_gap; + encodebin->paused_time = 0; + + GST_INFO_OBJECT (encodebin, "Encodebin now resumes. Offset delay [%"GST_TIME_FORMAT"], Total offset delay [%"GST_TIME_FORMAT"]" + , GST_TIME_ARGS(paused_gap) , GST_TIME_ARGS(encodebin->total_offset_time)); + } + else + { + encodebin->paused_time = 0; + encodebin->total_offset_time = 0; + + GST_WARNING_OBJECT (encodebin, "There is no clock in Encodebin."); + } + } + + //TODO : How about qos? + + //Unblock src of encode bin + if (!gst_encode_bin_block(encodebin, FALSE)) + { + GST_WARNING_OBJECT (encodebin, "Fail to Unblock Encodebin."); + goto resume_fail; + } +#if 0 //def GST_ENCODE_BIN_SIGNAL_ENABLE + g_signal_emit (G_OBJECT (encodebin), gst_encode_bin_signals[SIGNAL_STREAM_RESUME], 0, TRUE); +#endif + } + encodebin->pause = value; + return TRUE; + +pause_fail: + GST_WARNING_OBJECT (encodebin, "Fail to pause Encodebin"); +#ifdef GST_ENCODE_BIN_SIGNAL_ENABLE + g_signal_emit (G_OBJECT (encodebin), gst_encode_bin_signals[SIGNAL_STREAM_PAUSE], 0, FALSE); +#endif + return FALSE; + +resume_fail: + GST_WARNING_OBJECT (encodebin, "Fail to resume Encodebin"); +#ifdef GST_ENCODE_BIN_SIGNAL_ENABLE + g_signal_emit (G_OBJECT (encodebin), gst_encode_bin_signals[SIGNAL_STREAM_RESUME], 0, FALSE); +#endif + return FALSE; +} + +static gboolean +gst_encode_bin_release_pipeline (GstElement *element, + gpointer user_data) +{ +#if 0 + GstEncodeBin *encodebin = GST_ENCODE_BIN (element); + + gst_element_set_state (encodebin->audio_queue, GST_STATE_NULL); + gst_element_set_state (encodebin->audio_encode, GST_STATE_NULL); + gst_element_set_state (encodebin->video_queue, GST_STATE_NULL); + gst_element_set_state (encodebin->video_encode, GST_STATE_NULL); + gst_element_set_state (encodebin->mux, GST_STATE_NULL); + + if (encodebin->auto_video_scale) { + gst_element_set_state (encodebin->video_scale, GST_STATE_NULL); + gst_element_unlink (encodebin->video_queue, encodebin->video_scale); + gst_element_unlink (encodebin->video_scale, encodebin->video_encode); + gst_bin_remove (GST_BIN (element), encodebin->video_scale); + + encodebin->video_scale = NULL; + } else { + gst_element_unlink (encodebin->video_queue, encodebin->video_encode); + } + + gst_pad_unlink (gst_element_get_pad (encodebin->audio_encode, "src"), + encodebin->mux_audio_sinkpad); + gst_pad_unlink (gst_element_get_pad (encodebin->video_encode, "src"), + encodebin->mux_video_sinkpad); + + gst_bin_remove_many (GST_BIN (element), + encodebin->audio_queue, + encodebin->audio_encode, + encodebin->video_queue, + encodebin->video_encode, + encodebin->mux, + NULL); + + encodebin->audio_queue = NULL; + encodebin->audio_encode = NULL; + encodebin->video_queue = NULL; + encodebin->video_encode = NULL; + encodebin->mux = NULL; +#endif + return TRUE; +} + +static GstPadProbeReturn +gst_encode_bin_video_probe(GstPad *pad, GstPadProbeInfo *info, GstEncodeBin *encodebin) +{ + if (!encodebin) + { + GST_WARNING_OBJECT (encodebin, "encodebin is Null."); + return GST_PAD_PROBE_OK; + } + + //Adjusting timestamp of video source + GST_BUFFER_TIMESTAMP(gst_pad_probe_info_get_buffer(info)) -= encodebin->total_offset_time; + + return GST_PAD_PROBE_OK; +} + +static GstPadProbeReturn +gst_encode_bin_video_probe_hs(GstPad *pad, GstPadProbeInfo *info, GstEncodeBin *encodebin) +{ + if (!encodebin) + { + GST_WARNING_OBJECT (encodebin, "encodebin is Null."); + return GST_PAD_PROBE_OK; + } + + GST_BUFFER_TIMESTAMP(gst_pad_probe_info_get_buffer(info)) *= encodebin->multiple; + return GST_PAD_PROBE_OK; +} + +static GstPadProbeReturn +gst_encode_bin_audio_probe(GstPad *pad, GstPadProbeInfo *info, GstEncodeBin *encodebin) +{ + if (!encodebin) + { + GST_WARNING_OBJECT (encodebin, "encodebin is Null."); + return GST_PAD_PROBE_OK; + } + + //Adjusting timestamp of video source + GST_BUFFER_TIMESTAMP(gst_pad_probe_info_get_buffer(info)) -= encodebin->total_offset_time; + + return GST_PAD_PROBE_OK; +} + +static GstPad* +gst_encode_bin_get_mux_sink_pad(GstElement *mux, GstEncodeBinMuxSinkPad type) +{ + GstElementClass *elemclass = NULL; + GList *walk = NULL; + GstPad *pad = NULL; + + elemclass = GST_ELEMENT_GET_CLASS (mux); + + walk = gst_element_class_get_pad_template_list (elemclass); + + while (walk) { + GstPadTemplate *templ; + + templ = (GstPadTemplate *) walk->data; + if (GST_PAD_TEMPLATE_DIRECTION (templ) == GST_PAD_SINK) { + /* ENHANCE ME: Please add other specific mux's case */ + if (((type == ENCODEBIN_MUX_AUDIO_SINK) && strstr(GST_PAD_TEMPLATE_NAME_TEMPLATE (templ), "audio")) || //audio, audio_%d,... ex)ffmux_3gp + ((type == ENCODEBIN_MUX_VIDEO_SINK) && strstr(GST_PAD_TEMPLATE_NAME_TEMPLATE (templ), "video")) || //video, video_%d,... ex)ffmux_3gp + strstr(GST_PAD_TEMPLATE_NAME_TEMPLATE (templ), "sink") //sink, sink_%d, wavparse_sink, ... ex)oggmux, wavparse + ) { + g_print("PRINT TEMPLATE(%s)\n", GST_PAD_TEMPLATE_NAME_TEMPLATE (templ)); + pad = gst_element_get_request_pad (mux, GST_PAD_TEMPLATE_NAME_TEMPLATE (templ)); + break; + } + } + walk = g_list_next (walk); + } + + return pad; +} + +static gboolean +plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (gst_encode_bin_debug, "encodebin", 0, "encoder bin"); + +#ifdef ENABLE_NLS + GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE, + LOCALEDIR); + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); +#endif /* ENABLE_NLS */ + + return gst_element_register (plugin, "encodebin", GST_RANK_NONE, + GST_TYPE_ENCODE_BIN); +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + encodebin, + "EXT encoder bin", + plugin_init, VERSION, "LGPL", "Samsung Electronics Co", "http://www.samsung.com/") diff --git a/encodebin/src/gstencodebin.h b/encodebin/src/gstencodebin.h new file mode 100644 index 0000000..136fc92 --- /dev/null +++ b/encodebin/src/gstencodebin.h @@ -0,0 +1,159 @@ +/* + * GStreamer encodebin + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * 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_ENCODE_BIN_H__ +#define __GST_ENCODE_BIN_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_CAT_DEFAULT gst_encode_bin_debug + +#define GST_TYPE_ENCODE_BIN_PROFILE (gst_encode_bin_profile_get_type()) +GType gst_encode_bin_profile_get_type (void); + +#define GST_TYPE_ENCODE_BIN (gst_encode_bin_get_type()) +#define GST_ENCODE_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ENCODE_BIN,GstEncodeBin)) +#define GST_ENCODE_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ENCODE_BIN,GstEncodeBinClass)) +#define GST_IS_ENCODE_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ENCODE_BIN)) +#define GST_IS_ENCODE_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ENCODE_BIN)) + +#define GST_ENCODE_BIN_GET_LOCK(encodebin) (((GstEncodeBin*)encodebin)->mutex) +#define GST_ENCODE_BIN_LOCK(encodebin) g_mutex_lock (GST_ENCODE_BIN_GET_LOCK(encodebin)) +#define GST_ENCODE_BIN_UNLOCK(encodebin) g_mutex_unlock (GST_ENCODE_BIN_GET_LOCK(encodebin)) + +/* Signal enable */ +#define GST_ENCODE_BIN_SIGNAL_ENABLE + +typedef struct _GstEncodeBinPad { + GstCollectData *collect; + + gboolean is_video; + gboolean connected; + + gchar *tag; + + gst_riff_strh hdr; +} GstEncodeBinPad; + +typedef struct _GstEncodeBin GstEncodeBin; +typedef struct _GstEncodeBinClass GstEncodeBinClass; + +struct _GstEncodeBin +{ + GstBin bin; /* we extend GstBin */ + + GMutex *mutex; + + /* pads */ + GstPad *srcpad; + GstPad *video_sinkpad; + GstPad *audio_sinkpad; + GstPad *image_sinkpad; + GstPad *mux_audio_sinkpad; + GstPad *mux_video_sinkpad; + + /* sinkpads, video first */ + GSList *sinkpads; + + /* video restricted to 1 pad */ + guint video_pads, audio_pads; + + gint profile; + gint fps; + gint high_speed_fps; + gint multiple; + gchar *venc_name; + gchar *aenc_name; + gchar *ienc_name; + gchar *mux_name; + gchar *vconv_name; + + GstCaps *vcaps; + GstCaps *acaps; + GstCaps *icaps; + + gboolean auto_audio_convert; + gboolean auto_audio_resample; + gboolean auto_color_space; + gboolean block; + gboolean pause; + gboolean use_video_toggle; + gboolean use_venc_queue; + gboolean use_aenc_queue; + + GstElement *audio_queue; + GstElement *video_queue; + GstElement *video_encode_queue; + GstElement *audio_encode_queue; + GstElement *image_queue; + + GstElement *audio_encode; + GstElement *video_encode; + GstElement *image_encode; + + GstElement *vcapsfilter; + GstElement *acapsfilter; + GstElement *icapsfilter; + + GstElement *video_toggle; + GstElement *image_toggle; + GstElement *color_space; + GstElement *audio_conv; + GstElement *audio_sample; + + GstElement *mux; + + /* pause/resume variables */ + GstClockTime paused_time; /* pipeline time when pausing */ + GstClockTime total_offset_time; /* delayed time which is due to pause */ + gulong vsink_probeid; + gulong vsink_hs_probeid; + gulong asink_probeid; + gulong veque_sig_id; + gulong aeque_sig_id; +}; + +struct _GstEncodeBinClass +{ + GstBinClass parent_class; + +#ifdef GST_ENCODE_BIN_SIGNAL_ENABLE + /* signal we fire when stream block/pause function called */ + void (*stream_block) (GstElement * element, gboolean result); + void (*stream_unblock) (GstElement * element, gboolean result); + void (*stream_pause) (GstElement * element, gboolean result); + void (*stream_resume) (GstElement * element, gboolean result); +#endif + +}; + +GType gst_encode_bin_get_type (void); + +G_END_DECLS + + +#endif /* __GST_ENCODE_BIN_H__ */ diff --git a/evasimagesink/Makefile.am b/evasimagesink/Makefile.am new file mode 100644 index 0000000..308a09c --- /dev/null +++ b/evasimagesink/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/evasimagesink/src/Makefile.am b/evasimagesink/src/Makefile.am new file mode 100644 index 0000000..54a752d --- /dev/null +++ b/evasimagesink/src/Makefile.am @@ -0,0 +1,26 @@ +# Note: plugindir is set in configure + +############################################################################## +# TODO: change libgstevasimagesink.la to something else, e.g. libmysomething.la # +############################################################################## +plugin_LTLIBRARIES = libgstevasimagesink.la + +############################################################################## +# TODO: for the next set of variables, name the prefix if you named the .la, # +# e.g. libmysomething.la => libmysomething_la_SOURCES # +# libmysomething_la_CFLAGS # +# libmysomething_la_LIBADD # +# libmysomething_la_LDFLAGS # +############################################################################## + +# sources used to compile this plug-in +libgstevasimagesink_la_SOURCES = gstevasimagesink.c gstevasimagesink.h + +# compiler and linker flags used to compile this plugin, set in configure.ac +libgstevasimagesink_la_CFLAGS = $(GST_CFLAGS) $(GST_VIDEO_CFLAGS) $(EFL_CFLAGS) $(TBM_CFLAGS) +libgstevasimagesink_la_LIBADD = $(GST_LIBS) $(GST_VIDEO_LIBS) $(EFL_LIBS) $(TBM_LIBS) +libgstevasimagesink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstevasimagesink_la_LIBTOOLFLAGS = --tag=disable-static + +# headers we need but don't want installed +noinst_HEADERS = gstevasimagesink.h diff --git a/evasimagesink/src/gstevasimagesink.c b/evasimagesink/src/gstevasimagesink.c new file mode 100755 index 0000000..39f39ed --- /dev/null +++ b/evasimagesink/src/gstevasimagesink.c @@ -0,0 +1,2019 @@ +/* + * evasimagesink + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Sangchul Lee + * + * 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-evasimagesink + * Gstreamer Evas Video Sink - draw video on the given Evas Image Object + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "gstevasimagesink.h" + +#define CAP_WIDTH "width" +#define CAP_HEIGHT "height" +//#define DUMP_IMG + +GST_DEBUG_CATEGORY_STATIC (gst_evas_image_sink_debug); +#define GST_CAT_DEFAULT gst_evas_image_sink_debug + +/* Enumerations */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_EVAS_OBJECT, + PROP_EVAS_OBJECT_SHOW, +#ifdef USE_TBM_SURFACE + PROP_ROTATE_ANGLE, + PROP_DISPLAY_GEOMETRY_METHOD, + PROP_ENABLE_FLUSH_BUFFER, + PROP_FLIP +#endif +}; + +enum +{ + UPDATE_FALSE, + UPDATE_TRUE +}; + +#define COLOR_DEPTH 4 +#define GL_X11_ENGINE "gl_x11" +#define DO_RENDER_FROM_FIMC 1 +#define SIZE_FOR_UPDATE_VISIBILITY sizeof(gchar) + +#ifdef USE_TBM_SURFACE +#define MAX_ECOREPIPE_BUFFER_CNT 4 +#define DEBUGLOG_DEFAULT_COUNT 8 +#define SIZE_FOR_TBM_SUR_INDEX sizeof(gint) + +/* max channel count *********************************************************/ +#define SCMN_IMGB_MAX_PLANE (4) + +/* image buffer definition *************************************************** + + +------------------------------------------+ --- + | | ^ + | a[], p[] | | + | +---------------------------+ --- | | + | | | ^ | | + | |<---------- w[] ---------->| | | | + | | | | | | + | | | | + | | | h[] | e[] + | | | | + | | | | | | + | | | | | | + | | | v | | + | +---------------------------+ --- | | + | | v + +------------------------------------------+ --- + + |<----------------- s[] ------------------>| +*/ + +typedef struct +{ + /* width of each image plane */ + int w[SCMN_IMGB_MAX_PLANE]; + /* height of each image plane */ + int h[SCMN_IMGB_MAX_PLANE]; + /* stride of each image plane */ + int s[SCMN_IMGB_MAX_PLANE]; + /* elevation of each image plane */ + int e[SCMN_IMGB_MAX_PLANE]; + /* user space address of each image plane */ + void *a[SCMN_IMGB_MAX_PLANE]; + /* physical address of each image plane, if needs */ + void *p[SCMN_IMGB_MAX_PLANE]; + /* color space type of image */ + int cs; + /* left postion, if needs */ + int x; + /* top position, if needs */ + int y; + /* to align memory */ + int __dummy2; + /* arbitrary data */ + int data[16]; + /* dma buf fd */ + int fd[SCMN_IMGB_MAX_PLANE]; + /* buffer share method */ + int buf_share_method; + /* Y plane size in case of ST12 */ + int y_size; + /* UV plane size in case of ST12 */ + int uv_size; + /* Tizen buffer object */ + void *bo[SCMN_IMGB_MAX_PLANE]; + /* JPEG data */ + void *jpeg_data; + /* JPEG size */ + int jpeg_size; + /* TZ memory buffer */ + int tz_enable; +} SCMN_IMGB; +#endif + +#define EVASIMAGESINK_SET_EVAS_OBJECT_EVENT_CALLBACK( x_evas_image_object, x_usr_data ) \ +do \ +{ \ + if (x_evas_image_object) { \ + GST_LOG("object callback add"); \ + evas_object_event_callback_add (x_evas_image_object, EVAS_CALLBACK_DEL, evas_callback_del_event, x_usr_data); \ + evas_object_event_callback_add (x_evas_image_object, EVAS_CALLBACK_RESIZE, evas_callback_resize_event, x_usr_data); \ + } \ +}while(0) + +#define EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK( x_evas_image_object ) \ +do \ +{ \ + if (x_evas_image_object) { \ + GST_LOG("object callback del"); \ + evas_object_event_callback_del (x_evas_image_object, EVAS_CALLBACK_DEL, evas_callback_del_event); \ + evas_object_event_callback_del (x_evas_image_object, EVAS_CALLBACK_RESIZE, evas_callback_resize_event); \ + } \ +}while(0) + +#ifdef USE_TBM_SURFACE +#define EVASIMAGESINK_SET_EVAS_EVENT_CALLBACK( x_evas, x_usr_data ) \ +do \ +{ \ + if (x_evas) { \ + GST_DEBUG("callback add... evas_callback_render_pre.. evas : %p esink : %p", x_evas, x_usr_data); \ + evas_event_callback_add (x_evas, EVAS_CALLBACK_RENDER_PRE, evas_callback_render_pre, x_usr_data); \ + } \ +}while(0) + +#define EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK( x_evas ) \ +do \ +{ \ + if (x_evas) { \ + GST_DEBUG("callback del... evas_callback_render_pre"); \ + evas_event_callback_del (x_evas, EVAS_CALLBACK_RENDER_PRE, evas_callback_render_pre); \ + } \ +}while(0) +#endif + +GMutex *instance_lock; +guint instance_lock_count; + +static inline gboolean +is_evas_image_object (Evas_Object *obj) +{ + const char *type; + if (!obj) { + return FALSE; + } + type = evas_object_type_get (obj); + if (!type) { + return FALSE; + } + if (strcmp (type, "image") == 0) { + return TRUE; + } + return FALSE; +} + +#ifdef USE_TBM_SURFACE +gint +gst_evas_image_sink_ref_count (GstBuffer * buf) +{ + return GST_OBJECT_REFCOUNT_VALUE(GST_BUFFER_CAST(buf)); +} +#endif + +/* the capabilities of the inputs. + * + * BGRx format + */ +static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, +#ifdef USE_FIMCC + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE("BGRx"))); +#endif +#ifdef USE_TBM_SURFACE + GST_STATIC_CAPS(GST_VIDEO_CAPS_MAKE ("I420") ";" + GST_VIDEO_CAPS_MAKE ("NV12") ";" + GST_VIDEO_CAPS_MAKE ("SN12")) +); +#endif +#define _do_init \ + GST_DEBUG_CATEGORY_INIT (gst_evas_image_sink_debug, "evasimagesink", 0, "evasimagesink element"); +#define gst_evas_image_sink_parent_class parent_class + +G_DEFINE_TYPE_WITH_CODE (GstEvasImageSink, gst_evas_image_sink, GST_TYPE_VIDEO_SINK, _do_init); + +static void gst_evas_image_sink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gst_evas_image_sink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); +static void gst_evas_image_sink_finalize (GObject * object); +static gboolean gst_evas_image_sink_set_caps (GstBaseSink *base_sink, GstCaps *caps); +static GstFlowReturn gst_evas_image_sink_show_frame (GstVideoSink *video_sink, GstBuffer *buf); +static gboolean gst_evas_image_sink_event (GstBaseSink *sink, GstEvent *event); +static GstStateChangeReturn gst_evas_image_sink_change_state (GstElement *element, GstStateChange transition); +static void evas_callback_del_event (void *data, Evas *e, Evas_Object *obj, void *event_info); +static void evas_callback_resize_event (void *data, Evas *e, Evas_Object *obj, void *event_info); +#ifdef USE_TBM_SURFACE +static void evas_callback_render_pre (void *data, Evas *e, void *event_info); +static GstFlowReturn gst_esink_epipe_reset(GstEvasImageSink *esink); +static gboolean gst_esink_make_flush_buffer(GstEvasImageSink *esink); +static void _release_flush_buffer(GstEvasImageSink *esink); +static void gst_evas_image_sink_update_geometry (GstEvasImageSink *esink, GstVideoRectangle *result); +static void gst_evas_image_sink_apply_geometry (GstEvasImageSink *esink); +#endif +#ifdef DUMP_IMG +int util_write_rawdata (const char *file, const void *data, unsigned int size); +int g_cnt = 0; +#endif + +static void +gst_evas_image_sink_finalize (GObject * object) +{ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + + + +static void +gst_evas_image_sink_base_init (gpointer gclass) +{ +} + +static void +gst_evas_image_sink_class_init (GstEvasImageSinkClass *klass) +{ + GObjectClass *gobject_class; + GstBaseSinkClass *gstbasesink_class; + GstVideoSinkClass *gstvideosink_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstbasesink_class = GST_BASE_SINK_CLASS (klass); + gstvideosink_class = GST_VIDEO_SINK_CLASS (klass); + gstelement_class = (GstElementClass *) klass; + + gobject_class->set_property = gst_evas_image_sink_set_property; + gobject_class->get_property = gst_evas_image_sink_get_property; + gobject_class->finalize = gst_evas_image_sink_finalize; + + g_object_class_install_property (gobject_class, PROP_EVAS_OBJECT, + g_param_spec_pointer ("evas-object", "Destination Evas Object", + "Destination evas image object", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_EVAS_OBJECT_SHOW, + g_param_spec_boolean ("visible", "Show Evas Object", "When disabled, evas object does not show", + TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +#ifdef USE_TBM_SURFACE + g_object_class_install_property(gobject_class, PROP_ROTATE_ANGLE, + g_param_spec_int("rotate", "Rotate angle", "Rotate angle of display output", DEGREE_0, DEGREE_NUM, DEGREE_0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property(gobject_class, PROP_DISPLAY_GEOMETRY_METHOD, + g_param_spec_int("display-geometry-method", "Display geometry method", + "Geometrical method for display", DISP_GEO_METHOD_LETTER_BOX, DISP_GEO_METHOD_NUM, DISP_GEO_METHOD_LETTER_BOX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_ENABLE_FLUSH_BUFFER, + g_param_spec_boolean("enable-flush-buffer", "Enable flush buffer mechanism", + "Enable flush buffer mechanism when state change(PAUSED_TO_READY)", + TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property(gobject_class, PROP_FLIP, + g_param_spec_int("flip", "Display flip", + "Flip for display", FLIP_NONE, FLIP_NUM, FLIP_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +#endif + gst_element_class_set_static_metadata (gstelement_class, + "EvasImageSink", + "VideoSink", + "Video sink element for evas image object", + "Samsung Electronics "); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&sink_factory)); + + gstelement_class->change_state = GST_DEBUG_FUNCPTR(gst_evas_image_sink_change_state); + + gstvideosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_evas_image_sink_show_frame); + gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_evas_image_sink_set_caps); + gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_evas_image_sink_event); +} + +static void +gst_evas_image_sink_fini (gpointer data, GObject *obj) +{ + GST_INFO ("[ENTER]"); + + GstEvasImageSink *esink = GST_EVASIMAGESINK (obj); + if (!esink) { + return; + } +#ifdef USE_FIMCC + if (esink->oldbuf) { + gst_buffer_unref (esink->oldbuf); + } +#endif + + if (esink->eo) { +#ifdef USE_TBM_SURFACE + EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo)); + GST_DEBUG("unset EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK esink : %p, esink->eo : %x", esink, esink->eo); +#endif + EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo); + GST_DEBUG("unset EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK esink : %p, esink->eo : %x", esink, esink->eo); + evas_object_image_data_set(esink->eo, NULL); + } +#ifdef USE_TBM_SURFACE + if (esink->display_buffer_lock) { + g_mutex_free (esink->display_buffer_lock); + esink->display_buffer_lock = NULL; + } + if (esink->flow_lock) { + g_mutex_free (esink->flow_lock); + esink->flow_lock = NULL; + } + esink->eo = NULL; + esink->epipe = NULL; +#endif + g_mutex_lock (instance_lock); + instance_lock_count--; + g_mutex_unlock (instance_lock); + if (instance_lock_count == 0) { + g_mutex_free (instance_lock); + instance_lock = NULL; + } + + GST_DEBUG ("[LEAVE]"); +} + +#ifdef USE_TBM_SURFACE +static void +gst_evas_image_sink_reset (GstEvasImageSink *esink) +{ + int i = 0; + tbm_bo_handle bo_handle; + + GST_DEBUG("gst_evas_image_sink_reset start"); + + g_mutex_lock(esink->display_buffer_lock); + + for(i=0; idisplaying_buffer[i].tbm_surf) + { + tbm_surface_destroy(esink->displaying_buffer[i].tbm_surf); + esink->displaying_buffer[i].tbm_surf = NULL; + } + if(esink->displaying_buffer[i].buffer) + { + if(esink->displaying_buffer[i].ref_count) + { + if(esink->displaying_buffer[i].bo) { + bo_handle = tbm_bo_map(esink->displaying_buffer[i].bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE); + if (!bo_handle.ptr) { + GST_WARNING("failed to map bo [%p]", esink->displaying_buffer[i].bo); + } + else + tbm_bo_unmap(esink->displaying_buffer[i].bo); + } + else + GST_WARNING("there is no bo information. so skip to map bo"); + + GST_WARNING("[reset] unreffing gst %p", esink->displaying_buffer[i].buffer); + + while(esink->displaying_buffer[i].ref_count) + { + GST_WARNING("index[%d]'s buffer ref count=%d",i,gst_evas_image_sink_ref_count (esink->displaying_buffer[i].buffer)); + esink->displaying_buffer[i].ref_count--; + gst_buffer_unref(esink->displaying_buffer[i].buffer); + } + } + esink->displaying_buffer[i].buffer = NULL; + } + if(esink->displaying_buffer[i].bo) + esink->displaying_buffer[i].bo = NULL; + } + esink->prev_buf = NULL; + esink->prev_index = -1; + esink->cur_index = -1; + + esink->eo_size.x = esink->eo_size.y = + esink->eo_size.w = esink->eo_size.h = 0; + esink->use_ratio = FALSE; + esink->sent_buffer_cnt = 0; + + g_mutex_unlock(esink->display_buffer_lock); +} +#endif + +#ifdef USE_FIMCC +static void +evas_image_sink_cb_pipe (void *data, void *buffer, unsigned int nbyte) +#endif +#ifdef USE_TBM_SURFACE +static void +evas_image_sink_cb_pipe (void *data, int *buffer_index, unsigned int nbyte) +#endif +{ + GstEvasImageSink *esink = data; +#ifdef USE_FIMCC + GstBuffer *buf; + GstMapInfo buf_info = GST_MAP_INFO_INIT; + void *img_data; +#endif + GST_DEBUG ("[ENTER]"); + if (!esink || !esink->eo) { + GST_WARNING ("esink : %p, or eo is NULL returning", esink); + return; + } + GST_LOG("esink : %p, esink->eo : %x", esink, esink->eo); + if (nbyte == SIZE_FOR_UPDATE_VISIBILITY) { + if(!esink->object_show) { + evas_object_hide(esink->eo); + GST_INFO ("object hide.."); + } else { + evas_object_show(esink->eo); + GST_INFO ("object show.."); + } + GST_DEBUG ("[LEAVE]"); + return; + } +#ifdef USE_FIMCC + if (!buffer || nbyte != sizeof (GstBuffer *)) { + GST_WARNING ("buffer %p, nbyte : %d, sizeof(GstBuffer *) : %d", buffer, nbyte, sizeof (GstBuffer *)); + return; + } +#endif +#ifdef USE_TBM_SURFACE + int index = 0; + index = *buffer_index; + if ((index<0 || index>=TBM_SURFACE_NUM) || nbyte != SIZE_FOR_TBM_SUR_INDEX) { + GST_WARNING ("index : %d, nbyte : %d", index, nbyte); + return; + } +#endif + if (GST_STATE(esink) < GST_STATE_PAUSED) { + GST_WARNING ("WRONG-STATE(%d) for rendering, skip this frame", GST_STATE(esink)); + return; + } + +#ifdef USE_FIMCC + memcpy (&buf, buffer, sizeof (GstBuffer *)); + if (!buf) { + GST_ERROR ("There is no buffer"); + return; + } + if (esink->present_data_addr == -1) { + /* if present_data_addr is -1, we don't use this member variable */ + } else if (esink->present_data_addr != DO_RENDER_FROM_FIMC) { + GST_WARNING ("skip rendering this buffer, present_data_addr:%d, DO_RENDER_FROM_FIMC:%d", esink->present_data_addr, DO_RENDER_FROM_FIMC); + return; + } +#endif +#ifdef USE_TBM_SURFACE + g_mutex_lock(esink->display_buffer_lock); + if(esink->tbm_surface_format == TBM_FORMAT_NV12) { + if (!esink->displaying_buffer[index].tbm_surf) { + GST_ERROR("the index's nbuffer was already NULL, so return"); + g_mutex_unlock(esink->display_buffer_lock); + return; + } + GST_LOG("received (bo %p, gst %p) index num : %d", esink->displaying_buffer[index].bo, esink->displaying_buffer[index].buffer, index); + } else if(esink->tbm_surface_format == TBM_FORMAT_YUV420) { + GST_LOG("received (bo %p) index num : %d", esink->displaying_buffer[index].bo, index); + } + + Evas_Native_Surface surf; + surf.type = EVAS_NATIVE_SURFACE_TBM; + surf.version = EVAS_NATIVE_SURFACE_VERSION; + surf.data.tizen.buffer = esink->displaying_buffer[index].tbm_surf; + surf.data.tizen.rot = esink->rotate_angle; + surf.data.tizen.flip = esink->flip; + + GST_LOG("received (bo %p, gst %p) index num : %d", esink->displaying_buffer[index].bo, esink->displaying_buffer[index].buffer, index); + + GstVideoRectangle result = {0}; + + evas_object_geometry_get(esink->eo, &esink->eo_size.x, &esink->eo_size.y, &esink->eo_size.w, &esink->eo_size.h); + if (!esink->eo_size.w || !esink->eo_size.h) { + GST_ERROR ("there is no information for evas object size"); + g_mutex_unlock(esink->display_buffer_lock); + return; + } + gst_evas_image_sink_update_geometry(esink, &result); + if(!result.w || !result.h) + { + GST_ERROR("no information about geometry (%d, %d)", result.w, result.h); + g_mutex_unlock(esink->display_buffer_lock); + return; + } + + if(esink->use_ratio) + { + surf.data.tizen.ratio = (float) esink->w / esink->h; + GST_LOG("set ratio for letter mode"); + } + evas_object_size_hint_align_set(esink->eo, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_size_hint_weight_set(esink->eo, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + if ( !esink->is_evas_object_size_set && esink->w > 0 && esink->h > 0) { + evas_object_image_size_set(esink->eo, esink->w, esink->h); + esink->is_evas_object_size_set = TRUE; + } +#ifdef DUMP_IMG + int ret = 0; + char file_name[128]; + GST_INFO("[DUMP]"); + if(g_cnt<20) + { + sprintf(file_name, "DUMP_IMG_%2.2d.dump", g_cnt); + char *dump_data; + tbm_bo_handle vaddr_dump; + guint size = esink->w*esink->h + (esink->w/2*esink->h/2)*2; //this size is for I420 format + GST_WARNING ("DUMP IMG_%2.2d : buffer size(%d)", g_cnt, size); + dump_data = g_malloc(size); + vaddr_dump = tbm_bo_get_handle(esink->displaying_buffer[index].bo, TBM_DEVICE_CPU); + if (vaddr_dump.ptr) { + tbm_bo_unmap(esink->displaying_buffer[index].bo); + } + memcpy (dump_data, vaddr_dump.ptr, size); + ret = util_write_rawdata(file_name, dump_data, size); + if (ret) { + GST_ERROR_OBJECT (esink, "util_write_rawdata() failed"); + } else + g_cnt++; + g_free(dump_data); + } +#endif + evas_object_image_native_surface_set(esink->eo, &surf); + GST_DEBUG("native surface set finish"); + + if(result.x || result.y) + GST_LOG("coordinate x, y (%d, %d) for locating video to center", result.x, result.y); + evas_object_image_fill_set(esink->eo, result.x, result.y, result.w, result.h); + + evas_object_image_pixels_dirty_set(esink->eo, EINA_TRUE); + GST_DEBUG_OBJECT (esink, "GEO_METHOD : src(%dx%d), dst(%dx%d), dst_x(%d), dst_y(%d), rotate(%d), flip(%d)", + esink->w, esink->h, esink->eo_size.w, esink->eo_size.h, esink->eo_size.x, esink->eo_size.y, esink->rotate_angle, esink->flip); + + /* unref previous buffer */ + if(esink->tbm_surface_format == TBM_FORMAT_NV12) { + if(esink->prev_buf && esink->displaying_buffer[esink->prev_index].ref_count) + { + GST_DEBUG("before index %d's ref_count =%d, gst_buf %p",esink->prev_index,esink->displaying_buffer[esink->prev_index].ref_count, esink->prev_buf); + esink->displaying_buffer[esink->prev_index].ref_count--; + GST_DEBUG("after index %d's ref_count =%d, gst_buf %p",esink->prev_index,esink->displaying_buffer[esink->prev_index].ref_count, esink->prev_buf); + /* Print debug log for 8 frame */ + if(esink->debuglog_cnt_ecoreCbPipe > 0) + { + GST_WARNING("(%d) ecore_cb_pipe unref index[%d] .. gst_buf %p", DEBUGLOG_DEFAULT_COUNT-(esink->debuglog_cnt_ecoreCbPipe), esink->prev_index, esink->prev_buf); + esink->debuglog_cnt_ecoreCbPipe--; + } + if (esink->sent_buffer_cnt == MAX_ECOREPIPE_BUFFER_CNT) + GST_WARNING("sent buffer cnt 4->3 so skip will be stop"); + + esink->sent_buffer_cnt--; + GST_DEBUG("prev gst_buffer %p's unref Start!!", esink->prev_buf); + gst_buffer_unref(esink->prev_buf); + GST_DEBUG("prev gst_buffer %p's unref End!!", esink->prev_buf); + } else { + GST_DEBUG("ref_count=%d unref prev gst_buffer %p", esink->displaying_buffer[esink->prev_index].ref_count,esink->prev_buf); + } + + GST_DEBUG("Current gst_buf %p and index=%d is overwrited to Prev gst_buf %p & index %d", + esink->displaying_buffer[index].buffer, index, esink->prev_buf, esink->prev_index ); + esink->prev_buf = esink->displaying_buffer[index].buffer; + esink->prev_index = index; + }else if(esink->tbm_surface_format == TBM_FORMAT_YUV420) { + /* Print debug log for 8 frame */ + if(esink->debuglog_cnt_ecoreCbPipe > 0) + { + GST_WARNING("(%d) ecore_cb_pipe set index [%d] tbm_surf[%p]", + DEBUGLOG_DEFAULT_COUNT-(esink->debuglog_cnt_ecoreCbPipe), index, esink->displaying_buffer[index].tbm_surf); + esink->debuglog_cnt_ecoreCbPipe--; + } + if (esink->sent_buffer_cnt == MAX_ECOREPIPE_BUFFER_CNT) + GST_WARNING("sent buffer cnt 4->3 so skip will be stop"); + + esink->sent_buffer_cnt--; + } +#endif +#ifdef USE_FIMCC + if ( !esink->is_evas_object_size_set && esink->w > 0 && esink->h > 0) { + evas_object_image_size_set (esink->eo, esink->w, esink->h); + GST_DEBUG("evas_object_image_size_set(), width(%d),height(%d)", esink->w, esink->h); + esink->is_evas_object_size_set = TRUE; + } + if (esink->gl_zerocopy) { + img_data = evas_object_image_data_get (esink->eo, EINA_TRUE); + gst_buffer_map(buf, &buf_info, GST_MAP_READ); + if (!img_data || !buf_info.data) { + GST_WARNING ("Cannot get image data from evas object or cannot get gstbuffer data"); + evas_object_image_data_set(esink->eo, img_data); + } else { + GST_DEBUG ("img_data(%x), buf_info.data:%x, esink->w(%d),esink->h(%d), esink->eo(%x)",img_data,buf_info.data,esink->w,esink->h,esink->eo); + memcpy (img_data, buf_info.data, esink->w * esink->h * COLOR_DEPTH); + evas_object_image_pixels_dirty_set (esink->eo, 1); + evas_object_image_data_set(esink->eo, img_data); + } + gst_buffer_unmap(buf, &buf_info); + gst_buffer_unref (buf); + } else { + gst_buffer_map(buf, &buf_info, GST_MAP_READ); + GST_DEBUG ("buf_info.data(buf):%x, esink->eo(%x)",buf_info.data,esink->eo); + evas_object_image_data_set (esink->eo, buf_info.data); + gst_buffer_unmap(buf, &buf_info); + evas_object_image_pixels_dirty_set (esink->eo, 1); + if (esink->oldbuf) { + gst_buffer_unref(esink->oldbuf); + } + esink->oldbuf = buf; + } +#endif +#ifdef USE_TBM_SURFACE + g_mutex_unlock(esink->display_buffer_lock); +#endif + GST_DEBUG ("[LEAVE]"); +} +#ifdef USE_TBM_SURFACE +static void +gst_evas_image_sink_update_geometry (GstEvasImageSink *esink, GstVideoRectangle *result) +{ + if (!esink || !esink->eo) { + GST_WARNING("there is no esink"); + return; + } + + result->x = 0; + result->y = 0; + + switch (esink->display_geometry_method) + { + case DISP_GEO_METHOD_LETTER_BOX: // 0 + /* set black padding for letter box mode */ + GST_DEBUG("letter box mode"); + esink->use_ratio = TRUE; + result->w = esink->eo_size.w; + result->h = esink->eo_size.h; + break; + case DISP_GEO_METHOD_ORIGIN_SIZE: // 1 + GST_DEBUG("origin size mode"); + esink->use_ratio = FALSE; + /* set coordinate for each case */ + result->x = (esink->eo_size.w-esink->w) / 2; + result->y = (esink->eo_size.h-esink->h) / 2; + result->w = esink->w; + result->h = esink->h; + break; + case DISP_GEO_METHOD_FULL_SCREEN: // 2 + GST_DEBUG("full screen mode"); + esink->use_ratio = FALSE; + result->w = esink->eo_size.w; + result->h = esink->eo_size.h; + break; + case DISP_GEO_METHOD_CROPPED_FULL_SCREEN: // 3 + GST_DEBUG("cropped full screen mode"); + esink->use_ratio = FALSE; + /* compare evas object's ratio with video's */ + if((esink->eo_size.w/esink->eo_size.h) > (esink->w/esink->h)) + { + result->w = esink->eo_size.w; + result->h = esink->eo_size.w * esink->h / esink->w; + result->y = -(result->h-esink->eo_size.h) / 2; + } + else + { + result->w = esink->eo_size.h * esink->w / esink->h; + result->h = esink->eo_size.h; + result->x = -(result->w-esink->eo_size.w) / 2; + } + break; + case DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX: // 4 + GST_DEBUG("origin size or letter box mode"); + /* if video size is smaller than evas object's, it will be set to origin size mode */ + if((esink->eo_size.w > esink->w) && (esink->eo_size.h > esink->h)) + { + GST_DEBUG("origin size mode"); + esink->use_ratio = FALSE; + /* set coordinate for each case */ + result->x = (esink->eo_size.w-esink->w) / 2; + result->y = (esink->eo_size.h-esink->h) / 2; + result->w = esink->w; + result->h = esink->h; + } + else + { + GST_DEBUG("letter box mode"); + esink->use_ratio = TRUE; + result->w = esink->eo_size.w; + result->h = esink->eo_size.h; + } + break; + default: + GST_WARNING("unsupported mode."); + break; + } + GST_DEBUG("geometry result [%d, %d, %d, %d]", result->x, result->y, result->w, result->h); +} +static void +gst_evas_image_sink_apply_geometry (GstEvasImageSink *esink) +{ + if (!esink || !esink->eo) { + GST_WARNING("there is no esink"); + return; + } + + Evas_Native_Surface *surf = evas_object_image_native_surface_get(esink->eo); + GstVideoRectangle result = {0}; + + if(surf) + { + GST_DEBUG("native surface exists"); + surf->data.tizen.rot = esink->rotate_angle; + surf->data.tizen.flip = esink->flip; + evas_object_image_native_surface_set(esink->eo, surf); + + gst_evas_image_sink_update_geometry(esink, &result); + + if(esink->use_ratio) + { + surf->data.tizen.ratio = (float) esink->w / esink->h; + GST_LOG("set ratio for letter mode"); + } + + if(result.x || result.y) + GST_LOG("coordinate x, y (%d, %d) for locating video to center", result.x, result.y); + + evas_object_image_fill_set(esink->eo, result.x, result.y, result.w, result.h); + } + else + GST_WARNING("there is no surf"); +} +#endif + +static void +gst_evas_image_sink_init (GstEvasImageSink *esink) +{ + GST_INFO ("[ENTER]"); + + esink->eo = NULL; + esink->epipe = NULL; + esink->object_show = FALSE; + esink->update_visibility = UPDATE_FALSE; + esink->is_evas_object_size_set = FALSE; +#ifdef USE_FIMCC + esink->gl_zerocopy = FALSE; + esink->present_data_addr = -1; +#endif +#ifdef USE_TBM_SURFACE + esink->display_buffer_lock = g_mutex_new (); + esink->flow_lock = g_mutex_new (); + int i = 0; + for (i=0; idisplaying_buffer[i].tbm_surf = NULL; + esink->displaying_buffer[i].buffer = NULL; + esink->displaying_buffer[i].bo = NULL; + esink->displaying_buffer[i].ref_count = 0; + } + esink->prev_buf = NULL; + esink->prev_index = -1; + esink->cur_index = -1; + esink->enable_flush_buffer = TRUE; + esink->need_flush = FALSE; + esink->display_geometry_method = DISP_GEO_METHOD_LETTER_BOX; + esink->flip = FLIP_NONE; + esink->eo_size.x = esink->eo_size.y = + esink->eo_size.w = esink->eo_size.h = 0; + esink->use_ratio = FALSE; + esink->sent_buffer_cnt = 0; + esink->debuglog_cnt_showFrame = DEBUGLOG_DEFAULT_COUNT; + esink->debuglog_cnt_ecoreCbPipe = DEBUGLOG_DEFAULT_COUNT; + + esink->src_buf_idx = 0; + esink->is_buffer_allocated = FALSE; +#endif + if(!instance_lock) { + instance_lock = g_mutex_new(); + } + g_mutex_lock (instance_lock); + instance_lock_count++; + g_mutex_unlock (instance_lock); + + g_object_weak_ref (G_OBJECT (esink), gst_evas_image_sink_fini, NULL); + + GST_DEBUG ("[LEAVE]"); +} + +static void +evas_callback_del_event (void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + GST_INFO ("enter"); + + GstEvasImageSink *esink = data; + if (!esink) { + return; + } +#ifdef USE_FIMCC + if (esink->oldbuf) { + gst_buffer_unref (esink->oldbuf); + esink->oldbuf = NULL; + } +#endif + if (esink->eo) { +#ifdef USE_TBM_SURFACE + EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo)); + GST_DEBUG("unset EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK esink : %p, esink->eo : %x", esink, esink->eo); +#endif + EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo); + GST_DEBUG("unset EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK esink : %p, esink->eo : %x", esink, esink->eo); + + evas_object_image_data_set(esink->eo, NULL); + esink->eo = NULL; + } + GST_DEBUG ("[LEAVE]"); +} + +static void +evas_callback_resize_event (void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + int x, y, w, h; + x = y = w = h = 0; + + GST_DEBUG ("[ENTER]"); + + GstEvasImageSink *esink = data; + if (!esink || !esink->eo) { + return; + } + + evas_object_geometry_get(esink->eo, &x, &y, &w, &h); + if (!w || !h) { + GST_WARNING ("evas object size (w:%d,h:%d) was not set", w, h); + } else { +#ifdef USE_TBM_SURFACE + esink->eo_size.x = x; + esink->eo_size.y = y; + esink->eo_size.w = w; + esink->eo_size.h = h; + GST_WARNING ("resize (x:%d, y:%d, w:%d, h:%d)", x, y, w, h); + gst_evas_image_sink_apply_geometry(esink); +#endif +#ifdef USE_FIMCC + evas_object_image_fill_set(esink->eo, 0, 0, w, h); + GST_DEBUG ("evas object fill set (w:%d,h:%d)", w, h); +#endif + } + GST_DEBUG ("[LEAVE]"); +} +#ifdef USE_TBM_SURFACE +static void +evas_callback_render_pre (void *data, Evas *e, void *event_info) +{ + GstEvasImageSink *esink = data; + if (!esink || !esink->eo) { + GST_WARNING("there is no esink info.... esink : %p, or eo is NULL returning", esink); + return; + } + if(esink->need_flush && esink->flush_buffer) + { + g_mutex_lock(esink->display_buffer_lock); + Evas_Native_Surface surf; + GstVideoRectangle result = {0}; + + evas_object_geometry_get(esink->eo, &esink->eo_size.x, &esink->eo_size.y, &esink->eo_size.w, &esink->eo_size.h); + if (!esink->eo_size.w || !esink->eo_size.h) { + GST_ERROR ("there is no information for evas object size"); + return; + } + gst_evas_image_sink_update_geometry(esink, &result); + if(!result.w || !result.h) + { + GST_ERROR("no information about geometry (%d, %d)", result.w, result.h); + return; + } + + if(esink->use_ratio) + { + surf.data.tizen.ratio = (float) esink->w / esink->h; + GST_LOG("set ratio for letter mode"); + } + evas_object_size_hint_align_set(esink->eo, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_size_hint_weight_set(esink->eo, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + if ( !esink->is_evas_object_size_set && esink->w > 0 && esink->h > 0) { + evas_object_image_size_set(esink->eo, esink->w, esink->h); + esink->is_evas_object_size_set = TRUE; + } + + if(result.x || result.y) + GST_LOG("coordinate x, y (%d, %d) for locating video to center", result.x, result.y); + + evas_object_image_fill_set(esink->eo, result.x, result.y, result.w, result.h); + + surf.type = EVAS_NATIVE_SURFACE_TBM; + surf.version = EVAS_NATIVE_SURFACE_VERSION; + surf.data.tizen.buffer = esink->flush_buffer->tbm_surf; + surf.data.tizen.rot = esink->rotate_angle; + surf.data.tizen.flip = esink->flip; + GST_DEBUG("use esink->flush buffer->tbm_surf (%p), rotate(%d), flip(%d)", + esink->flush_buffer->tbm_surf, esink->rotate_angle, esink->flip); + evas_object_image_native_surface_set(esink->eo, &surf); + g_mutex_unlock(esink->display_buffer_lock); + esink->need_flush = FALSE; + } + evas_object_image_pixels_dirty_set (esink->eo, EINA_TRUE); + GST_LOG("dirty set finish"); +} + +static gboolean +gst_evas_image_sink_release_source_buffer(GstEvasImageSink *esink) +{ + int i = 0; + tbm_bo_handle bo_handle; + g_mutex_lock(esink->display_buffer_lock); + + for(i = 0; i < TBM_SURFACE_NUM; i++) { + GST_WARNING("[reset] reset gst %p", esink->displaying_buffer[i].buffer); + esink->displaying_buffer[i].bo = NULL; + esink->displaying_buffer[i].tbm_surf = NULL; + esink->displaying_buffer[i].ref_count = 0; + } + + for(i = 0; i < SOURCE_BUFFER_NUM; i++) { + if(esink->src_buffer_info[i].bo) { + tbm_bo_unmap(esink->src_buffer_info[i].bo); + esink->src_buffer_info[i].bo = NULL; + } + + if (esink->src_buffer_info[i].tbm_surf) { + tbm_surface_destroy(esink->src_buffer_info[i].tbm_surf); + esink->src_buffer_info[i].tbm_surf = NULL; + } + } + + esink->is_buffer_allocated = FALSE; + esink->src_buf_idx = 0; + esink->prev_buf = NULL; + esink->prev_index = -1; + esink->cur_index = -1; + + esink->eo_size.x = esink->eo_size.y = + esink->eo_size.w = esink->eo_size.h = 0; + esink->use_ratio = FALSE; + esink->sent_buffer_cnt = 0; + + g_mutex_unlock(esink->display_buffer_lock); + + return TRUE; +} + +static gboolean +gst_evas_image_sink_allocate_source_buffer(GstEvasImageSink *esink) +{ + int size = 0; + int idx = 0; + tbm_bo bo; + tbm_bo_handle vaddr; + GstFlowReturn ret=GST_FLOW_OK; + + if (esink == NULL) { + GST_ERROR("handle is NULL"); + return FALSE; + } + + for(idx=0; idx < SOURCE_BUFFER_NUM; idx++) { + if(!esink->src_buffer_info[idx].tbm_surf) { + /* create tbm surface */ + esink->src_buffer_info[idx].tbm_surf = tbm_surface_create(esink->w, esink->h, esink->tbm_surface_format); + } + if(!esink->src_buffer_info[idx].tbm_surf) + { + GST_ERROR("tbm_surf is NULL!!"); + goto ALLOC_FAILED; + } + + /* get bo and size */ + bo = tbm_surface_internal_get_bo(esink->src_buffer_info[idx].tbm_surf, 0); + size = tbm_bo_size(bo); + if(!bo || !size) + { + GST_ERROR("bo(%p), size(%d)", bo, size); + goto ALLOC_FAILED; + } + esink->src_buffer_info[idx].bo = bo; + + vaddr = tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE); + if (!vaddr.ptr) { + GST_WARNING_OBJECT(esink, "get vaddr failed pointer = %p", vaddr.ptr); + tbm_bo_unmap(bo); + goto ALLOC_FAILED; + } else { + memset (vaddr.ptr, 0x0, size); + GST_LOG_OBJECT (esink, "tbm_bo_map(VADDR) finished, bo(%p), vaddr(%p)", bo, vaddr.ptr); + } + + esink->src_buffer_info[idx].usr_addr = vaddr.ptr; + + GST_WARNING_OBJECT(esink, "src buffer index:%d , tbm surface : %p", idx, esink->src_buffer_info[idx].tbm_surf); + } + + return TRUE; + +ALLOC_FAILED: + gst_evas_image_sink_release_source_buffer(esink); + return FALSE; +} +#endif + +static int +evas_image_sink_get_size_from_caps (GstCaps *caps, int *w, int *h) +{ + gboolean r; + int width, height; + GstStructure *s; + + if (!caps || !w || !h) { + return -1; + } + s = gst_caps_get_structure (caps, 0); + if (!s) { + return -1; + } + + r = gst_structure_get_int (s, CAP_WIDTH, &width); + if (r == FALSE) { + GST_DEBUG("fail to get width from caps"); + return -1; + } + + r = gst_structure_get_int (s, CAP_HEIGHT, &height); + if (r == FALSE) { + GST_DEBUG("fail to get height from caps"); + return -1; + } + + *w = width; + *h = height; + GST_DEBUG ("size w(%d), h(%d)", width, height); + + return 0; +} +#ifdef USE_FIMCC +static gboolean +is_zerocopy_supported (Evas *e) +{ + Eina_List *engines, *l; + int cur_id; + int id; + char *name; + + if (!e) { + return FALSE; + } + + engines = evas_render_method_list (); + if (!engines) { + return FALSE; + } + + cur_id = evas_output_method_get (e); + + EINA_LIST_FOREACH (engines, l, name) { + id = evas_render_method_lookup (name); + if (name && id == cur_id) { + if (!strcmp (name, GL_X11_ENGINE)) { + return TRUE; + } + break; + } + } + return FALSE; +} + +static int +evas_image_sink_event_parse_data (GstEvasImageSink *esink, GstEvent *event) +{ + const GstStructure *st; + guint st_data_addr = 0; + gint st_data_width = 0; + gint st_data_height = 0; + + g_return_val_if_fail (event != NULL, FALSE); + g_return_val_if_fail (esink != NULL, FALSE); + + if (GST_EVENT_TYPE (event) != GST_EVENT_CUSTOM_DOWNSTREAM_OOB) { + GST_WARNING ("it's not a custom downstream oob event"); + return -1; + } + st = gst_event_get_structure (event); + if (st == NULL || !gst_structure_has_name (st, "GstStructureForCustomEvent")) { + GST_WARNING ("structure in a given event is not proper"); + return -1; + } + if (!gst_structure_get_uint (st, "data-addr", &st_data_addr)) { + GST_WARNING ("parsing data-addr failed"); + return -1; + } + esink->present_data_addr = st_data_addr; + + return 0; +} +#endif +static gboolean +gst_evas_image_sink_event (GstBaseSink *sink, GstEvent *event) +{ +#ifdef USE_FIMCC + GstEvasImageSink *esink = GST_EVASIMAGESINK (sink); + GstMessage *msg; + gchar *str; +#endif + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_START: + GST_DEBUG ("GST_EVENT_FLUSH_START"); + break; + case GST_EVENT_FLUSH_STOP: + GST_DEBUG ("GST_EVENT_FLUSH_STOP"); + break; + case GST_EVENT_EOS: + GST_DEBUG ("GST_EVENT_EOS"); + break; +#ifdef USE_FIMCC + case GST_EVENT_CUSTOM_DOWNSTREAM_OOB: + if(!evas_image_sink_event_parse_data(esink, event)) { + GST_DEBUG ("GST_EVENT_CUSTOM_DOWNSTREAM_OOB, present_data_addr:%x",esink->present_data_addr); + } else { + GST_ERROR ("evas_image_sink_event_parse_data() failed"); + } + break; +#endif + default: + break; + } + if (GST_BASE_SINK_CLASS (gst_evas_image_sink_parent_class)->event) { + return GST_BASE_SINK_CLASS (gst_evas_image_sink_parent_class)->event (sink, event); + } else { + return TRUE; + } +} + +static GstStateChangeReturn +gst_evas_image_sink_change_state (GstElement *element, GstStateChange transition) +{ + GstStateChangeReturn ret_state = GST_STATE_CHANGE_SUCCESS; + GstEvasImageSink *esink = NULL; + GstFlowReturn ret=GST_FLOW_OK; + esink = GST_EVASIMAGESINK(element); + + if(!esink) { + GST_ERROR("can not get evasimagesink from element"); + return GST_STATE_CHANGE_FAILURE; + } + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + GST_WARNING ("*** STATE_CHANGE_NULL_TO_READY ***"); +#ifdef USE_TBM_SURFACE + g_mutex_lock (esink->flow_lock); + if (!is_evas_image_object (esink->eo)) { + GST_ERROR_OBJECT (esink, "There is no evas image object.."); + g_mutex_unlock (esink->flow_lock); + return GST_STATE_CHANGE_FAILURE; + } + g_mutex_unlock (esink->flow_lock); +#endif + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + GST_WARNING ("*** STATE_CHANGE_READY_TO_PAUSED ***"); + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: +#ifdef USE_TBM_SURFACE + /* Print debug log for 8 frame */ + esink->debuglog_cnt_showFrame = DEBUGLOG_DEFAULT_COUNT; + esink->debuglog_cnt_ecoreCbPipe = DEBUGLOG_DEFAULT_COUNT; +#endif + GST_WARNING ("*** STATE_CHANGE_PAUSED_TO_PLAYING ***"); + break; + default: + break; + } + + ret_state = GST_ELEMENT_CLASS (gst_evas_image_sink_parent_class)->change_state (element, transition); + + switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + GST_WARNING ("*** STATE_CHANGE_PLAYING_TO_PAUSED ***"); + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + GST_WARNING ("*** STATE_CHANGE_PAUSED_TO_READY ***"); +#ifdef USE_TBM_SURFACE + Eina_Bool r; + /* flush buffer, we will copy last buffer to keep image data and reset buffer list */ + GST_WARNING("esink->enable_flush_buffer : %d", esink->enable_flush_buffer); + if(esink->enable_flush_buffer && esink->tbm_surface_format == TBM_FORMAT_NV12) + { + if (gst_esink_make_flush_buffer(esink) == FALSE) { + ret = gst_esink_epipe_reset(esink); + if(ret) { + GST_ERROR_OBJECT(esink, "evas epipe reset ret=%d, need to check",ret); + return GST_STATE_CHANGE_FAILURE; + } + gst_evas_image_sink_reset(esink); + } + } + else { + ret = gst_esink_epipe_reset(esink); + if(ret) { + GST_ERROR_OBJECT(esink, "evas epipe reset ret=%d, need to check",ret); + return GST_STATE_CHANGE_FAILURE; + } + if(esink->tbm_surface_format == TBM_FORMAT_NV12) { + gst_evas_image_sink_reset(esink); + } else if(esink->tbm_surface_format == TBM_FORMAT_YUV420) { + gst_evas_image_sink_release_source_buffer(esink); + } + } +#endif + break; + case GST_STATE_CHANGE_READY_TO_NULL: + GST_WARNING ("*** STATE_CHANGE_READY_TO_NULL ***"); +#ifdef USE_TBM_SURFACE + if(esink->flush_buffer) + _release_flush_buffer(esink); + EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo)); +#endif + EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo); + if (esink->epipe) { + GST_DEBUG("ecore-pipe will delete"); + ecore_pipe_del (esink->epipe); + esink->epipe = NULL; + } + break; + default: + break; + } + + return ret_state; +} + +static void +gst_evas_image_sink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstEvasImageSink *esink = GST_EVASIMAGESINK (object); + Evas_Object *eo; + + g_mutex_lock (instance_lock); + + switch (prop_id) { + case PROP_EVAS_OBJECT: + eo = g_value_get_pointer (value); + if (is_evas_image_object (eo)) { + if (eo != esink->eo) { + Eina_Bool r; +#ifdef USE_TBM_SURFACE + EVASIMAGESINK_UNSET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo)); +#endif + /* delete evas object callbacks registrated on a previous evas image object */ + EVASIMAGESINK_UNSET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo); + esink->eo = eo; + + /* add evas object callbacks on a new evas image object */ + EVASIMAGESINK_SET_EVAS_OBJECT_EVENT_CALLBACK (esink->eo, esink); +#ifdef USE_TBM_SURFACE + GST_WARNING("register render callback [esink : %p, esink->eo : %x]", esink, esink->eo); + EVASIMAGESINK_SET_EVAS_EVENT_CALLBACK (evas_object_evas_get(esink->eo), esink); + evas_object_geometry_get(esink->eo, &esink->eo_size.x, &esink->eo_size.y, &esink->eo_size.w, &esink->eo_size.h); + GST_WARNING ("evas object size (x:%d, y:%d, w:%d, h:%d)", esink->eo_size.x, esink->eo_size.y, esink->eo_size.w, esink->eo_size.h); +#endif +#ifdef USE_FIMCC + esink->gl_zerocopy = is_zerocopy_supported (evas_object_evas_get (eo)); + if (esink->gl_zerocopy) { + evas_object_image_content_hint_set (esink->eo, EVAS_IMAGE_CONTENT_HINT_DYNAMIC); + GST_DEBUG("Enable gl zerocopy"); + } +#endif + GST_DEBUG("Evas Image Object(%x) is set", esink->eo); + esink->is_evas_object_size_set = FALSE; + esink->object_show = TRUE; + esink->update_visibility = UPDATE_TRUE; + if (esink->epipe) { + r = ecore_pipe_write (esink->epipe, &esink->update_visibility, SIZE_FOR_UPDATE_VISIBILITY); + if (r == EINA_FALSE) { + GST_WARNING ("Failed to ecore_pipe_write() for updating visibility\n"); + } + } + } + } else { + GST_ERROR ("Cannot set evas-object property: value is not an evas image object"); + } + break; + + case PROP_EVAS_OBJECT_SHOW: + { + Eina_Bool r; + esink->object_show = g_value_get_boolean (value); + if( !is_evas_image_object(esink->eo) ) { + GST_WARNING ("Cannot apply visible(show-object) property: cannot get an evas object\n"); + break; + } + esink->update_visibility = UPDATE_TRUE; + GST_LOG("esink->update_visibility : %d", esink->update_visibility); + if (esink->epipe) { + r = ecore_pipe_write (esink->epipe, &esink->update_visibility, SIZE_FOR_UPDATE_VISIBILITY); + if (r == EINA_FALSE) { + GST_WARNING ("Failed to ecore_pipe_write() for updating visibility)\n"); + } + } + break; + } +#ifdef USE_TBM_SURFACE + case PROP_ROTATE_ANGLE: + { + int rotate = 0; + rotate = g_value_get_int (value); + switch(rotate) + { + case DEGREE_0: + esink->rotate_angle = 0; + break; + case DEGREE_90: + esink->rotate_angle = 90; + break; + case DEGREE_180: + esink->rotate_angle = 180; + break; + case DEGREE_270: + esink->rotate_angle = 270; + break; + default: + break; + } + GST_INFO("update rotate_angle : %d", esink->rotate_angle); + break; + } + case PROP_DISPLAY_GEOMETRY_METHOD: + { + Eina_Bool r; + guint geometry = g_value_get_int (value); + if (esink->display_geometry_method != geometry) { + esink->display_geometry_method = geometry; + GST_INFO_OBJECT (esink, "Overlay geometry method update, display_geometry_method(%d)", esink->display_geometry_method); + } + + g_mutex_lock(esink->display_buffer_lock); + + if(esink->cur_index!=-1 && esink->epipe) + { + GST_WARNING("apply property esink->cur_index =%d",esink->cur_index); + esink->displaying_buffer[esink->cur_index].ref_count++; + gst_buffer_ref(esink->displaying_buffer[esink->cur_index].buffer); + esink->sent_buffer_cnt++; + r = ecore_pipe_write (esink->epipe, &esink->cur_index, SIZE_FOR_TBM_SUR_INDEX); + + if (r == EINA_FALSE) { + GST_WARNING("ecore_pipe_write fail"); + esink->displaying_buffer[esink->cur_index].ref_count--; + gst_buffer_unref(esink->displaying_buffer[esink->cur_index].buffer); + esink->sent_buffer_cnt--; + } + } + g_mutex_unlock(esink->display_buffer_lock); + break; + } + case PROP_ENABLE_FLUSH_BUFFER: + esink->enable_flush_buffer = g_value_get_boolean(value); + break; + case PROP_FLIP: + { + esink->flip = g_value_get_int(value); + GST_INFO("update flip : %d", esink->flip); + break; + } +#endif + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + + g_mutex_unlock (instance_lock); +} + +static void +gst_evas_image_sink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstEvasImageSink *esink = GST_EVASIMAGESINK (object); + + switch (prop_id) { + case PROP_EVAS_OBJECT: + g_value_set_pointer (value, esink->eo); + break; + case PROP_EVAS_OBJECT_SHOW: + g_value_set_boolean (value, esink->object_show); + break; +#ifdef USE_TBM_SURFACE + case PROP_ROTATE_ANGLE: + g_value_set_int (value, esink->rotate_angle); + break; + case PROP_DISPLAY_GEOMETRY_METHOD: + g_value_set_int (value, esink->display_geometry_method); + break; + case PROP_ENABLE_FLUSH_BUFFER: + g_value_set_boolean(value, esink->enable_flush_buffer); + break; + case PROP_FLIP: + g_value_set_int(value, esink->flip); + break; +#endif + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_evas_image_sink_set_caps (GstBaseSink *base_sink, GstCaps *caps) +{ + int r; + int w, h; + GstEvasImageSink *esink = GST_EVASIMAGESINK (base_sink); + GstStructure *structure = NULL; + gchar *format = NULL; + + esink->is_evas_object_size_set = FALSE; + r = evas_image_sink_get_size_from_caps (caps, &w, &h); + if (!r) { + esink->w = w; + esink->h = h; + GST_DEBUG ("set size w(%d), h(%d)", w, h); + } + + structure = gst_caps_get_structure (caps, 0); + if (!structure) { + return FALSE; + } + + if ((format = gst_structure_get_string (structure, "format"))) { + + GST_DEBUG ("format(dst) is not set...it may be rgb series"); + } + + GST_DEBUG_OBJECT(esink, "source color format is %s", format); +#ifdef USE_TBM_SURFACE + if (!strcmp (format, "SN12") || !strcmp (format, "NV12")) + esink->tbm_surface_format = TBM_FORMAT_NV12; + else if (!strcmp (format, "I420")) + esink->tbm_surface_format = TBM_FORMAT_YUV420; + else { + GST_ERROR("cannot parse fourcc format from caps."); + return FALSE; + } +#endif + + return TRUE; +} + +static GstFlowReturn +gst_evas_image_sink_show_frame (GstVideoSink *video_sink, GstBuffer *buf) +{ + GstEvasImageSink *esink = GST_EVASIMAGESINK (video_sink); + Eina_Bool r; + GstMapInfo buf_info = GST_MAP_INFO_INIT; + + GST_LOG("[ENTER] show frame"); +#ifdef USE_TBM_SURFACE + if (!gst_evas_image_sink_ref_count (buf)) + { + GST_WARNING("ref count is 0.. skip show frame"); + return GST_FLOW_OK; + } +#endif + g_mutex_lock (instance_lock); +#ifdef USE_FIMCC + if (esink->present_data_addr == -1) { + /* if present_data_addr is -1, we don't use this member variable */ + } else if (esink->present_data_addr != DO_RENDER_FROM_FIMC) { + GST_WARNING ("skip rendering this buffer, present_data_addr:%d, DO_RENDER_FROM_FIMC:%d", + esink->present_data_addr, DO_RENDER_FROM_FIMC); + g_mutex_unlock (instance_lock); + return GST_FLOW_OK; + } +#endif + if (!esink->epipe) { + esink->epipe = ecore_pipe_add ((Ecore_Pipe_Cb)evas_image_sink_cb_pipe, esink); + if (!esink->epipe) { + GST_ERROR ("ecore-pipe create failed"); + g_mutex_unlock (instance_lock); + return GST_FLOW_ERROR; + } + GST_DEBUG("ecore-pipe create success"); + } +#ifdef USE_TBM_SURFACE + int i = 0; + int index = -1; + SCMN_IMGB *scmn_imgb = NULL; + gboolean exist_bo = FALSE; + gst_buffer_map(buf, &buf_info, GST_MAP_READ); + + GST_LOG ("BUF: gst_buf= %p dts= %" GST_TIME_FORMAT " pts= %" GST_TIME_FORMAT " size= %lu, mallocdata= %p", + buf, GST_TIME_ARGS(GST_BUFFER_DTS (buf)), GST_TIME_ARGS(GST_BUFFER_PTS (buf)), buf_info.size, buf_info.memory); + + if(esink->tbm_surface_format == TBM_FORMAT_NV12) { + /* get received buffer informations */ + scmn_imgb = (SCMN_IMGB *)buf_info.memory; + if (!scmn_imgb) { + GST_WARNING("scmn_imgb is NULL. Skip..." ); + gst_buffer_unmap(buf, &buf_info); + g_mutex_unlock (instance_lock); + return GST_FLOW_OK; + } + if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER) + { + /* check whether bo is new or not */ + for(i=0; idisplaying_buffer[i].bo==scmn_imgb->bo[0]) + { + GST_DEBUG("it is already saved bo %p (index num : %d)", esink->displaying_buffer[i].bo, i); + index = i; + exist_bo = TRUE; + break; + } + else + exist_bo = FALSE; + } + /* keep bo */ + if(!exist_bo) + { + /* find empty buffer space for indexing */ + for(i=0; idisplaying_buffer[i].bo) + { + index = i; + break; + } + } + if(index!=-1) + { + /* keep informations */ + esink->displaying_buffer[index].buffer = buf; + esink->displaying_buffer[index].bo = scmn_imgb->bo[0]; + GST_WARNING("TBM bo %p / gst_buf %p", esink->displaying_buffer[index].bo, esink->displaying_buffer[index].buffer); + + /* create new tbm surface */ + esink->displaying_buffer[index].tbm_surf = tbm_surface_internal_create_with_bos(esink->w, esink->h, + TBM_FORMAT_NV12, esink->displaying_buffer[index].bo, TBM_BO_DEFAULT); + if(!esink->displaying_buffer[index].tbm_surf) + { + GST_WARNING("there is no tbm surface.. bo : %p, gst_buf : %p", esink->displaying_buffer[index].bo, esink->displaying_buffer[index].buffer); + gst_buffer_unmap(buf, &buf_info); + g_mutex_unlock (instance_lock); + return GST_FLOW_OK; + } + + GST_WARNING("create tbm surface : %p", esink->displaying_buffer[index].tbm_surf); + } + } + /* because it has same bo, use existing tbm surface */ + else + { + if(index!=-1) + { + esink->displaying_buffer[index].buffer = buf; + GST_DEBUG("existing tbm surface %p.. bo %p, gst_buf %p", esink->displaying_buffer[index].tbm_surf, esink->displaying_buffer[index].bo, esink->displaying_buffer[index].buffer); + exist_bo = FALSE; + } + } + + /* if it couldn't find proper index */ + if(index == -1) + GST_WARNING("all spaces are using!!!"); + else + GST_DEBUG("selected buffer index %d", index); + + } + else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FLUSH_BUFFER) + { + /* flush buffer, we will copy last buffer to keep image data and reset buffer list */ + GST_WARNING_OBJECT(esink, "FLUSH_BUFFER: gst_buf= %p dts= %" GST_TIME_FORMAT " pts= %" GST_TIME_FORMAT " size= %lu, mallocdata= %p", + buf, GST_TIME_ARGS(GST_BUFFER_DTS (buf)), GST_TIME_ARGS(GST_BUFFER_PTS (buf)), buf_info.size, buf_info.memory); + gst_buffer_ref (buf); + if (gst_esink_make_flush_buffer(esink)) + GST_WARNING("made flush buffer"); + gst_buffer_unref (buf); + } + else + { + GST_ERROR("it is not TBM buffer.. %d", scmn_imgb->buf_share_method); + } + } else if(esink->tbm_surface_format == TBM_FORMAT_YUV420) { + static int skip_count_i420=0; + if(esink->sent_buffer_cnt >= MAX_ECOREPIPE_BUFFER_CNT) { + if(!(skip_count_i420++%20)) { + GST_WARNING("[%d]EA buffer was already sent to ecore pipe, and %d frame skipped", esink->sent_buffer_cnt,skip_count_i420); + } + gst_buffer_unmap(buf, &buf_info); + g_mutex_unlock (instance_lock); + return GST_FLOW_OK; + } + + if(!esink->is_buffer_allocated) { + /* Allocate TBM buffer for non-zero copy case */ + if(!gst_evas_image_sink_allocate_source_buffer(esink)) { + GST_ERROR_OBJECT(esink, "Buffer allocation failed"); + gst_buffer_unmap(buf, &buf_info); + g_mutex_unlock (instance_lock); + return GST_FLOW_ERROR; + } + esink->is_buffer_allocated = TRUE; + } + + skip_count_i420 = 0; //for skip log in I420 + + /* check whether bo is new or not */ + for(i=0; idisplaying_buffer[i].bo == esink->src_buffer_info[esink->src_buf_idx].bo) { + GST_DEBUG_OBJECT(esink, "it is already saved bo %p (index num : %d)", esink->displaying_buffer[i].bo, i); + index = i; + exist_bo = TRUE; + break; + } + else + exist_bo = FALSE; + } + + /* keep bo */ + if(!exist_bo) { + /* find empty buffer space for indexing */ + for(i=0; idisplaying_buffer[i].bo) { + index = i; + break; + } + } + + if(index!=-1) { + /* keep informations */ + esink->displaying_buffer[index].bo = esink->src_buffer_info[esink->src_buf_idx].bo; + esink->displaying_buffer[index].tbm_surf = esink->src_buffer_info[esink->src_buf_idx].tbm_surf; + + GST_DEBUG_OBJECT(esink, "gst_buf %p, TBM bo %p.. gst_buf vaddr %p .. src data size(%lu)", + buf, esink->displaying_buffer[index].bo, buf_info.data, buf_info.size); + + memcpy(esink->src_buffer_info[esink->src_buf_idx].usr_addr, buf_info.data, buf_info.size); + } + } else { + /* because it has same bo, use existing tbm surface */ + if(index!=-1) { + memcpy(esink->src_buffer_info[esink->src_buf_idx].usr_addr, buf_info.data, buf_info.size); + + GST_DEBUG_OBJECT(esink, "existing tbm surface %p.. gst_buf %p, bo %p, gst_buf vaddr %p", + esink->displaying_buffer[index].tbm_surf, buf, esink->displaying_buffer[index].bo, buf_info.data); + exist_bo = FALSE; + } + } + + /* if it couldn't find proper index */ + if(index == -1) + GST_WARNING_OBJECT(esink, "all spaces are being used!!!"); + else + GST_DEBUG_OBJECT(esink, "selected buffer index %d", index); + + } else { + GST_ERROR_OBJECT(esink, "unsupported color format"); + gst_buffer_unmap(buf, &buf_info); + g_mutex_unlock (instance_lock); + return GST_FLOW_ERROR; + } +#endif + if (esink->object_show) { //if (esink->object_show && index != -1) +#ifdef USE_FIMCC + gst_buffer_ref (buf); + r = ecore_pipe_write (esink->epipe, &buf, sizeof (GstBuffer *)); + if (r == EINA_FALSE) { + //add error handling + GST_WARNING("ecore_pipe_write fail"); + gst_buffer_unref (buf); + } +#endif +#ifdef USE_TBM_SURFACE + int old_curidx=esink->cur_index ; + static int skip_count=0; + g_mutex_lock(esink->display_buffer_lock); + + if(esink->tbm_surface_format == TBM_FORMAT_NV12 && scmn_imgb->buf_share_method != BUF_SHARE_METHOD_FLUSH_BUFFER) { + if (esink->sent_buffer_cnt < MAX_ECOREPIPE_BUFFER_CNT) { + GST_LOG("[show_frame] before refcount : %d .. gst_buf : %p", gst_evas_image_sink_ref_count (buf), buf); + gst_buffer_ref (buf); + esink->displaying_buffer[index].ref_count++; + esink->cur_index = index; + GST_LOG("index %d set refcount increase as %d", index,esink->displaying_buffer[index].ref_count); + GST_LOG("[show_frame] after refcount : %d .. gst_buf : %p", gst_evas_image_sink_ref_count (buf), buf); + + /* Print debug log for 8 frame */ + if(esink->debuglog_cnt_showFrame > 0) + { + GST_WARNING("(%d) ecore_pipe_write index[%d] gst_buf : %p", DEBUGLOG_DEFAULT_COUNT-(esink->debuglog_cnt_showFrame), + esink->cur_index, esink->displaying_buffer[esink->cur_index].buffer); + esink->debuglog_cnt_showFrame--; + } + + esink->sent_buffer_cnt++; + skip_count =0 ; + + r = ecore_pipe_write (esink->epipe, &esink->cur_index , SIZE_FOR_TBM_SUR_INDEX); + + if (r == EINA_FALSE) { + GST_LOG("[show_frame] before refcount : %d .. gst_buf : %p", gst_evas_image_sink_ref_count (buf), buf); + esink->cur_index = old_curidx; + if(esink->displaying_buffer[index].ref_count) + { + esink->displaying_buffer[index].ref_count--; + esink->sent_buffer_cnt--; + gst_buffer_unref(buf); + GST_ERROR("finish unreffing"); + } + } + } else { + /* If buffer count which is sent to ecore pipe, is upper 3, Print Error log */ + if(!(skip_count++%20)) { + GST_WARNING("[%d]EA buffer was already sent to ecore pipe, and %d frame skipped", esink->sent_buffer_cnt,skip_count); + } + } + } else if (esink->tbm_surface_format == TBM_FORMAT_YUV420) { + esink->cur_index = index; + GST_LOG("index %d", index); + GST_LOG("[show_frame] gst_buf vaddr %p", esink->src_buffer_info[esink->src_buf_idx].usr_addr); + + /* Print debug log for 8 frame */ + if(esink->debuglog_cnt_showFrame > 0) + { + GST_WARNING("(%d) ecore_pipe_write : index[%d], bo[%p], tbm_surf[%p], gst_buf[%p], gst_buf vaddr [%p]", DEBUGLOG_DEFAULT_COUNT-(esink->debuglog_cnt_showFrame), + esink->cur_index, esink->displaying_buffer[index].bo, esink->displaying_buffer[index].tbm_surf, buf, esink->src_buffer_info[esink->src_buf_idx].usr_addr); + esink->debuglog_cnt_showFrame--; + } + + esink->sent_buffer_cnt++; + + esink->src_buf_idx++; + r = ecore_pipe_write (esink->epipe, &esink->cur_index , SIZE_FOR_TBM_SUR_INDEX); + + if (r == EINA_FALSE) { + esink->cur_index = old_curidx; + esink->sent_buffer_cnt--; + esink->src_buf_idx--; + GST_ERROR("ecore_pipe_write is failed. index[%d], bo[%p], tbm_surf[%p], gst_buf vaddr [%p]", + index, esink->displaying_buffer[index].bo, esink->displaying_buffer[index].tbm_surf, esink->src_buffer_info[esink->src_buf_idx].usr_addr); + } + esink->src_buf_idx = esink->src_buf_idx % SOURCE_BUFFER_NUM; + } + + g_mutex_unlock(esink->display_buffer_lock); +#endif + GST_DEBUG ("ecore_pipe_write() was called with gst_buf= %p.. gst_buf Vaddr=%p, mallocdata= %p", buf, buf_info.size, buf_info.memory); + } else { + GST_WARNING ("skip ecore_pipe_write(). becuase of esink->object_show(%d) index(%d)", esink->object_show, index); + } + gst_buffer_unmap(buf, &buf_info); + g_mutex_unlock (instance_lock); + GST_DEBUG ("Leave"); + return GST_FLOW_OK; +} + +#ifdef USE_TBM_SURFACE +static GstFlowReturn +gst_esink_epipe_reset(GstEvasImageSink *esink) +{ + if (esink == NULL) { + GST_ERROR("handle is NULL"); + return GST_FLOW_ERROR; + } + + if (esink->epipe) { + GST_DEBUG("ecore-pipe will delete"); + ecore_pipe_del (esink->epipe); + esink->epipe = NULL; + } + + if (!esink->epipe) { + esink->epipe = ecore_pipe_add ((Ecore_Pipe_Cb)evas_image_sink_cb_pipe, esink); + if (!esink->epipe) { + GST_ERROR ("ecore-pipe create failed"); + return GST_FLOW_ERROR; + } + GST_DEBUG("ecore-pipe create success"); + } + + return GST_FLOW_OK; +} + + +static gboolean gst_esink_make_flush_buffer(GstEvasImageSink *esink) +{ + GstEvasImageFlushBuffer *flush_buffer = NULL; + GstEvasImageDisplayingBuffer *display_buffer = NULL; + int size = 0; + tbm_bo bo; + tbm_bo_handle vaddr_src; + tbm_bo_handle vaddr_dst; + GstFlowReturn ret=GST_FLOW_OK; + int src_size = 0; + + if (esink == NULL) { + GST_ERROR("handle is NULL"); + return FALSE; + } + + if (esink->cur_index == -1) { + GST_WARNING_OBJECT(esink, "there is no remained buffer"); + return FALSE; + } + + if(esink->flush_buffer) + _release_flush_buffer(esink); + + /* malloc buffer */ + flush_buffer = (GstEvasImageFlushBuffer *)malloc(sizeof(GstEvasImageFlushBuffer)); + if (flush_buffer == NULL) { + GST_ERROR_OBJECT(esink, "GstEvasImageFlushBuffer alloc failed"); + return FALSE; + } + + memset(flush_buffer, 0x0, sizeof(GstEvasImageFlushBuffer)); + + display_buffer = &(esink->displaying_buffer[esink->cur_index]); + GST_WARNING_OBJECT(esink, "cur_index [%d]", + esink->cur_index); + if(!display_buffer || !display_buffer->bo) + { + GST_WARNING("display_buffer(%p) or bo (%p) is NULL!!", display_buffer, display_buffer->bo); + goto FLUSH_BUFFER_FAILED; + } + + /* create tbm surface */ + flush_buffer->tbm_surf = tbm_surface_create(esink->w, esink->h, TBM_FORMAT_NV12); + + if(!flush_buffer->tbm_surf) + { + GST_ERROR("tbm_surf is NULL!!"); + goto FLUSH_BUFFER_FAILED; + } + + /* get bo and size */ + bo = tbm_surface_internal_get_bo(flush_buffer->tbm_surf, 0); + size = tbm_bo_size(bo); + if(!bo || !size) + { + GST_ERROR("bo(%p), size(%d)", bo, size); + goto FLUSH_BUFFER_FAILED; + } + flush_buffer->bo = bo; + + src_size = gst_buffer_get_size(display_buffer->buffer); + + vaddr_src = tbm_bo_map(display_buffer->bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE); + vaddr_dst = tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE); + if (!vaddr_src.ptr || !vaddr_dst.ptr) { + GST_WARNING_OBJECT(esink, "get vaddr failed src %p, dst %p", vaddr_src.ptr, vaddr_dst.ptr); + if (vaddr_src.ptr) { + tbm_bo_unmap(display_buffer->bo); + } + if (vaddr_dst.ptr) { + tbm_bo_unmap(bo); + } + goto FLUSH_BUFFER_FAILED; + } else { + memset (vaddr_dst.ptr, 0x0, size); + GST_WARNING_OBJECT (esink, "tbm_bo_map(VADDR) finished, bo(%p), vaddr(%p)", bo, vaddr_dst.ptr); + } + + /* copy buffer */ + memcpy(vaddr_dst.ptr, vaddr_src.ptr, src_size); + + tbm_bo_unmap(display_buffer->bo); + tbm_bo_unmap(bo); + + GST_WARNING_OBJECT(esink, "copy done.. tbm surface : %p src_size : %d", flush_buffer->tbm_surf, src_size); + + esink->flush_buffer = flush_buffer; + + /* initialize buffer list */ + if (esink->object_show) + esink->need_flush = TRUE; + + ret = gst_esink_epipe_reset(esink); + if(ret) { + GST_ERROR_OBJECT(esink, "evas epipe reset ret=%d, need to check",ret); + return FALSE; + } else { + GST_ERROR_OBJECT(esink, "evas epipe reset success"); + } + + gst_evas_image_sink_reset(esink); + + + return TRUE; + +FLUSH_BUFFER_FAILED: + if (flush_buffer) { + if(flush_buffer->tbm_surf) + { + tbm_surface_destroy(flush_buffer->tbm_surf); + flush_buffer->tbm_surf = NULL; + } + + free(flush_buffer); + flush_buffer = NULL; + } + return FALSE; +} + + static void _release_flush_buffer(GstEvasImageSink *esink) +{ + if (esink == NULL || + esink->flush_buffer == NULL) { + GST_WARNING("handle is NULL"); + return; + } + + GST_WARNING_OBJECT(esink, "release FLUSH BUFFER start"); + if (esink->flush_buffer->bo) { + esink->flush_buffer->bo = NULL; + } + if(esink->flush_buffer->tbm_surf) { + tbm_surface_destroy(esink->flush_buffer->tbm_surf); + esink->flush_buffer->tbm_surf = NULL; + } + + GST_WARNING_OBJECT(esink, "release FLUSH BUFFER done"); + + free(esink->flush_buffer); + esink->flush_buffer = NULL; + + return; +} +#endif +#ifdef DUMP_IMG +int util_write_rawdata(const char *file, const void *data, unsigned int size) +{ + FILE *fp; + fp = fopen(file, "wb"); + if (fp == NULL) + return -1; + fwrite((char*)data, sizeof(char), size, fp); + fclose(fp); + return 0; +} +#endif + +static gboolean +evas_image_sink_init (GstPlugin *evasimagesink) +{ + GST_DEBUG_CATEGORY_INIT (gst_evas_image_sink_debug, "evasimagesink", 0, "Evas image object based videosink"); + + return gst_element_register (evasimagesink, "evasimagesink", GST_RANK_NONE, GST_TYPE_EVASIMAGESINK); +} + +#ifndef PACKAGE +#define PACKAGE "gstevasimagesink-plugin-package" +#endif + +GST_PLUGIN_DEFINE ( + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + evasimagesink, + "Evas image object based videosink", + evas_image_sink_init, + VERSION, + "LGPL", + "Samsung Electronics Co", + "http://www.samsung.com/" +) diff --git a/evasimagesink/src/gstevasimagesink.h b/evasimagesink/src/gstevasimagesink.h new file mode 100644 index 0000000..acc1882 --- /dev/null +++ b/evasimagesink/src/gstevasimagesink.h @@ -0,0 +1,170 @@ +/* + * evasimagesink + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Sangchul Lee + * + * 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_EVASIMAGESINK_H__ +#define __GST_EVASIMAGESINK_H__ + +//#define USE_TBM_SURFACE +#define USE_FIMCC + +#include +#include +#include +#include +#ifdef USE_TBM_SURFACE +#include +#include +#endif +G_BEGIN_DECLS + +/* #defines don't like whitespacey bits */ +#define GST_TYPE_EVASIMAGESINK \ + (gst_evas_image_sink_get_type()) +#define GST_EVASIMAGESINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_EVASIMAGESINK,GstEvasImageSink)) +#define GST_EVASIMAGESINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_EVASIMAGESINK,GstEvasImageSinkClass)) +#define GST_IS_EVASIMAGESINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_EVASIMAGESINK)) +#define GST_IS_EVASIMAGESINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_EVASIMAGESINK)) + +typedef struct _GstEvasImageSink GstEvasImageSink; +typedef struct _GstEvasImageSinkClass GstEvasImageSinkClass; +#ifdef USE_TBM_SURFACE +typedef struct _GstEvasImageDisplayingBuffer GstEvasImageDisplayingBuffer; +typedef struct _GstEvasImageFlushBuffer GstEvasImageFlushBuffer; +typedef enum { + BUF_SHARE_METHOD_NONE = -1, + BUF_SHARE_METHOD_PADDR = 0, + BUF_SHARE_METHOD_FD, + BUF_SHARE_METHOD_TIZEN_BUFFER, + BUF_SHARE_METHOD_FLUSH_BUFFER +} buf_share_method_t; + +enum { + DEGREE_0 = 0, + DEGREE_90, + DEGREE_180, + DEGREE_270, + DEGREE_NUM, +}; + +enum { + DISP_GEO_METHOD_LETTER_BOX = 0, + DISP_GEO_METHOD_ORIGIN_SIZE, + DISP_GEO_METHOD_FULL_SCREEN, + DISP_GEO_METHOD_CROPPED_FULL_SCREEN, + DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX, + DISP_GEO_METHOD_CUSTOM_DST_ROI, + DISP_GEO_METHOD_NUM, +}; + +enum { + FLIP_NONE = 0, + FLIP_HORIZONTAL, + FLIP_VERTICAL, + FLIP_BOTH, + FLIP_NUM +}; + +struct buffer_info { + uint64_t usr_addr; + uint64_t size; + void *bo; + tbm_surface_h tbm_surf; +}; + +/* _GstEvasDisplayingBuffer + * + * buffer : manage ref count by got index through comparison + * bo : compare with buffer from codec for getting index + * n_buffer : compare with buffer from evas for getting index + * ref_count : decide whether it unref buffer or not in gst_evas_image_sink_fini/reset + */ +struct _GstEvasImageDisplayingBuffer { + GstBuffer *buffer; + void *bo; + tbm_surface_h tbm_surf; + int ref_count; +}; + +struct _GstEvasImageFlushBuffer { + void *bo; + tbm_surface_h tbm_surf; +}; +#define TBM_SURFACE_NUM 20 +#define SOURCE_BUFFER_NUM 8 +#endif +struct _GstEvasImageSink +{ + GstVideoSink element; + + Evas_Object *eo; + Ecore_Pipe *epipe; + Evas_Coord w; + Evas_Coord h; + gboolean object_show; + gchar update_visibility; + gboolean gl_zerocopy; + + GstBuffer *oldbuf; + + gboolean is_evas_object_size_set; + guint present_data_addr; +#ifdef USE_TBM_SURFACE + GMutex *display_buffer_lock; + GMutex *flow_lock; + GstEvasImageDisplayingBuffer displaying_buffer[TBM_SURFACE_NUM]; + GstVideoRectangle eo_size; + gboolean use_ratio; + guint rotate_angle; + guint display_geometry_method; + guint flip; + GstBuffer *prev_buf; + gint prev_index; + gint cur_index; + gboolean need_flush; + gboolean enable_flush_buffer; + GstEvasImageFlushBuffer *flush_buffer; + gint sent_buffer_cnt; + gint debuglog_cnt_showFrame; + gint debuglog_cnt_ecoreCbPipe; + + tbm_format tbm_surface_format; + struct buffer_info src_buffer_info[TBM_SURFACE_NUM]; + guint src_buf_idx; + gboolean is_buffer_allocated; +#endif +}; + +struct _GstEvasImageSinkClass +{ + GstVideoSinkClass parent_class; +}; + +GType gst_evas_image_sink_get_type (void); + +G_END_DECLS + +#endif /* __GST_EVASIMAGESINK_H__ */ diff --git a/evaspixmapsink/Makefile.am b/evaspixmapsink/Makefile.am new file mode 100644 index 0000000..d02b8d7 --- /dev/null +++ b/evaspixmapsink/Makefile.am @@ -0,0 +1,14 @@ +plugin_LTLIBRARIES = libgstevaspixmapsink.la + +libgstevaspixmapsink_la_SOURCES = evaspixmapsink.c +libgstevaspixmapsink_la_CFLAGS = $(GST_CFLAGS) $(X_CFLAGS) $(EFL_CFLAGS) \ + $(XFIXES_CFLAGS) $(DRI2PROTO_CFLAGS) $(DRI2_CFLAGS) $(X11_CFLAGS) $(XDAMAGE_CFLAGS) $(XV_CFLAGS) +libgstevaspixmapsink_la_LIBADD = \ + $(GST_LIBS) -lgstvideo-$(GST_MAJORMINOR) \ + $(X_LIBS) $(XVIDEO_LIBS) $(XSHM_LIBS) $(LIBM) \ + $(EFL_LIBS) \ + $(XFIXES_LIBS) $(DRI2PROTO_LIBS) $(DRI2_LIBS) $(X11_LIBS) $(XDAMAGE_LIBS) $(XV_LIBS) +libgstevaspixmapsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstxvimagesink_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = evaspixmapsink.h diff --git a/evaspixmapsink/evaspixmapsink.c b/evaspixmapsink/evaspixmapsink.c new file mode 100755 index 0000000..532c123 --- /dev/null +++ b/evaspixmapsink/evaspixmapsink.c @@ -0,0 +1,3755 @@ +/* + * EvasPixmapSink + * + * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Sangchul Lee + * + * 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 + +/* Our interfaces */ +#include +#include +//#include +#include +/* Helper functions */ +#include + +/* Object header */ +#include "evaspixmapsink.h" + +#ifdef GST_EXT_XV_ENHANCEMENT +/* Samsung extension headers */ +/* For xv extension header for buffer transfer (output) */ +#include "xv_types.h" + +/* headers for drm */ +#include +#include +#include +#include +#include +#include +#include + +//#define DUMP_IMG +#ifdef DUMP_IMG +#include +#endif +typedef enum { + BUF_SHARE_METHOD_PADDR = 0, + BUF_SHARE_METHOD_FD +} buf_share_method_t; + +/* max channel count *********************************************************/ +#define SCMN_IMGB_MAX_PLANE (4) + +/* image buffer definition *************************************************** + + +------------------------------------------+ --- + | | ^ + | a[], p[] | | + | +---------------------------+ --- | | + | | | ^ | | + | |<---------- w[] ---------->| | | | + | | | | | | + | | | | + | | | h[] | e[] + | | | | + | | | | | | + | | | | | | + | | | v | | + | +---------------------------+ --- | | + | | v + +------------------------------------------+ --- + + |<----------------- s[] ------------------>| +*/ + +typedef struct +{ + /* width of each image plane */ + int w[SCMN_IMGB_MAX_PLANE]; + /* height of each image plane */ + int h[SCMN_IMGB_MAX_PLANE]; + /* stride of each image plane */ + int s[SCMN_IMGB_MAX_PLANE]; + /* elevation of each image plane */ + int e[SCMN_IMGB_MAX_PLANE]; + /* user space address of each image plane */ + void * a[SCMN_IMGB_MAX_PLANE]; + /* physical address of each image plane, if needs */ + void * p[SCMN_IMGB_MAX_PLANE]; + /* color space type of image */ + int cs; + /* left postion, if needs */ + int x; + /* top position, if needs */ + int y; + /* to align memory */ + int __dummy2; + /* arbitrary data */ + int data[16]; + /* dma buf fd */ + int dma_buf_fd[SCMN_IMGB_MAX_PLANE]; + /* buffer share method */ + int buf_share_method; +} SCMN_IMGB; +#endif + +/* Debugging category */ +#include +GST_DEBUG_CATEGORY_STATIC (gst_debug_evaspixmapsink); +#define GST_CAT_DEFAULT gst_debug_evaspixmapsink +GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE); + +#ifdef GST_EXT_XV_ENHANCEMENT + +enum { + DEGREE_0, + DEGREE_90, + DEGREE_180, + DEGREE_270, + DEGREE_NUM, +}; + +enum { + DISP_GEO_METHOD_LETTER_BOX = 0, + DISP_GEO_METHOD_ORIGIN_SIZE, + DISP_GEO_METHOD_FULL_SCREEN, + DISP_GEO_METHOD_CROPPED_FULL_SCREEN, + DISP_GEO_METHOD_CUSTOM_ROI, + DISP_GEO_METHOD_NUM, +}; + +#define DEF_DISPLAY_GEOMETRY_METHOD DISP_GEO_METHOD_LETTER_BOX + +#define GST_TYPE_EVASPIXMAPSINK_DISPLAY_GEOMETRY_METHOD (gst_evaspixmapsink_display_geometry_method_get_type()) + +static GType +gst_evaspixmapsink_display_geometry_method_get_type(void) +{ + static GType evaspixmapsink_display_geometry_method_type = 0; + static const GEnumValue display_geometry_method_type[] = { + { 0, "Letter box", "LETTER_BOX"}, + { 1, "Origin size", "ORIGIN_SIZE"}, + { 2, "Full-screen", "FULL_SCREEN"}, + { 3, "Cropped Full-screen", "CROPPED_FULL_SCREEN"}, + { 4, "Explicitely described destination ROI", "CUSTOM_ROI"}, + { 5, NULL, NULL}, + }; + + if (!evaspixmapsink_display_geometry_method_type) { + evaspixmapsink_display_geometry_method_type = g_enum_register_static("GstEvasPixmapSinkDisplayGeometryMethodType", display_geometry_method_type); + } + + return evaspixmapsink_display_geometry_method_type; +} +#endif /* GST_EXT_XV_ENHANCEMENT */ + +typedef struct +{ + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long input_mode; + unsigned long status; +} +MotifWmHints, MwmHints; + +#define MWM_HINTS_DECORATIONS (1L << 1) + +static void gst_evaspixmapsink_reset (GstEvasPixmapSink *evaspixmapsink); +static void gst_evaspixmap_buffer_finalize (GstEvasPixmapBuffer *evaspixmapbuf); +static void gst_evaspixmapsink_navigation_init (GstNavigationInterface *iface); +static void gst_evaspixmapsink_colorbalance_init (GstColorBalanceInterface *iface); +static void gst_evaspixmapsink_property_probe_interface_init (GstPropertyProbeInterface *iface); +static void gst_evaspixmapsink_xcontext_clear (GstEvasPixmapSink *evaspixmapsink); +static void gst_evaspixmapsink_xpixmap_destroy (GstEvasPixmapSink *evaspixmapsink, GstXPixmap *xpixmap); +static void gst_evaspixmapsink_xpixmap_update_geometry (GstEvasPixmapSink *evaspixmapsink); +static gboolean gst_evaspixmap_buffer_put (GstEvasPixmapSink *evaspixmapsink, GstEvasPixmapBuffer *evaspixmapbuf); +static gboolean gst_evaspixmapsink_xpixmap_link (GstEvasPixmapSink *evaspixmapsink); +static void gst_evaspixmapsink_xpixmap_clear (GstEvasPixmapSink *evaspixmapsink, GstXPixmap *xpixmap); +static gint gst_evaspixmapsink_get_format_from_caps (GstEvasPixmapSink *evaspixmapsink, GstCaps *caps); +static void drm_close_gem(GstEvasPixmapSink *evaspixmapsink, unsigned int gem_handle); +#ifdef DUMP_IMG +int util_write_rawdata (const char *file, const void *data, unsigned int size); +int g_cnt = 0; +#endif +/* Default template - initiated with class struct to allow gst-register to work + without X running */ +static GstStaticPadTemplate gst_evaspixmapsink_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 ]") + ); + +enum +{ + PROP_0, + PROP_CONTRAST, + PROP_BRIGHTNESS, + PROP_HUE, + PROP_SATURATION, + PROP_DISPLAY, + PROP_SYNCHRONOUS, + PROP_PIXEL_ASPECT_RATIO, + PROP_FORCE_ASPECT_RATIO, + PROP_DEVICE, + PROP_DEVICE_NAME, + PROP_DOUBLE_BUFFER, + PROP_AUTOPAINT_COLORKEY, + PROP_COLORKEY, + PROP_PIXMAP_WIDTH, + PROP_PIXMAP_HEIGHT, +#ifdef GST_EXT_XV_ENHANCEMENT + PROP_DISPLAY_GEOMETRY_METHOD, + PROP_ZOOM, + PROP_DST_ROI_X, + PROP_DST_ROI_Y, + PROP_DST_ROI_W, + PROP_DST_ROI_H, + PROP_STOP_VIDEO, +#endif + PROP_EVAS_OBJECT, + PROP_VISIBLE, + PROP_ORIGIN_SIZE, +}; + +#define gst_evaspixmapsink_parent_class parent_class + +/* ============================================================= */ +/* */ +/* Private Methods */ +/* */ +/* ============================================================= */ + +/* evaspixmap buffers */ + +#define GST_TYPE_EVASPIXMAP_BUFFER (gst_evaspixmap_buffer_get_type()) + +#define GST_IS_EVASPIXMAP_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_EVASPIXMAP_BUFFER)) +#define GST_EVASPIXMAP_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_EVASPIXMAP_BUFFER, GstEvasPixmapBuffer)) + +G_DEFINE_BOXED_TYPE(GstEvasPixmapBuffer, gst_evaspixmap_buffer, NULL, gst_evaspixmap_buffer_finalize); + +static void +ecore_pipe_callback_handler (void *data, void *buffer, unsigned int nbyte) +{ + GstEvasPixmapSink *evaspixmapsink = (GstEvasPixmapSink*)data; + GST_DEBUG_OBJECT (evaspixmapsink,"[START]"); + + if (!data ) { + GST_WARNING_OBJECT (evaspixmapsink,"data is NULL.."); + return; + } + if (!evaspixmapsink->eo) { + GST_WARNING_OBJECT (evaspixmapsink,"evas object is NULL.."); + return; + } + + /* mapping evas object with xpixmap */ + if (evaspixmapsink->do_link) { + GST_DEBUG_OBJECT (evaspixmapsink,"do link"); + if (evaspixmapsink->xpixmap->pixmap) { + Evas_Native_Surface surf; + surf.version = EVAS_NATIVE_SURFACE_VERSION; + surf.type = EVAS_NATIVE_SURFACE_X11; + surf.data.x11.visual = ecore_x_default_visual_get(ecore_x_display_get(), ecore_x_default_screen_get()); + surf.data.x11.pixmap = evaspixmapsink->xpixmap->pixmap; + evas_object_image_native_surface_set(evaspixmapsink->eo, &surf); + evaspixmapsink->do_link = FALSE; + } else { + GST_WARNING_OBJECT (evaspixmapsink,"pixmap is NULL.."); + return; + } + } else { + GST_DEBUG_OBJECT (evaspixmapsink,"update"); + /* update evas image object size */ + if (evaspixmapsink->use_origin_size) { + evas_object_geometry_get(evaspixmapsink->eo, NULL, NULL, &evaspixmapsink->w, &evaspixmapsink->h); + } + evas_object_image_pixels_dirty_set (evaspixmapsink->eo, 1); + evas_object_image_fill_set(evaspixmapsink->eo, 0, 0, evaspixmapsink->w, evaspixmapsink->h); + evas_object_image_data_update_add(evaspixmapsink->eo, 0, 0, evaspixmapsink->w, evaspixmapsink->h); + } + + GST_DEBUG_OBJECT (evaspixmapsink,"[END]"); +} + +static void +evas_callback_resize_event (void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + int w = 0; + int h = 0; + float former_ratio = 0; + float ratio = 0; + float abs_margin = 0; + + GstEvasPixmapSink *evaspixmapsink = (GstEvasPixmapSink *)data; + GST_DEBUG_OBJECT (evaspixmapsink,"[START]"); + + evas_object_geometry_get(evaspixmapsink->eo, NULL, NULL, &w, &h); + GST_DEBUG_OBJECT (evaspixmapsink,"resized : w(%d), h(%d)", w, h); + if (!evaspixmapsink->use_origin_size && + (evaspixmapsink->w != w || evaspixmapsink->h != h)) { + former_ratio = (float)evaspixmapsink->w / evaspixmapsink->h; + ratio = (float)w / h; + evaspixmapsink->w = w; + evaspixmapsink->h = h; + +#ifdef COMPARE_RATIO + GST_DEBUG_OBJECT (evaspixmapsink,"resized : ratio(%.3f=>%.3f)", former_ratio, ratio); + if ( former_ratio >= ratio ) { + abs_margin = former_ratio - ratio; + } else { + abs_margin = ratio - former_ratio; + } + /* re-link_pixmap can only be set when ratio is changed */ + if ( abs_margin >= MARGIN_OF_ERROR ) { +#endif + if (!gst_evaspixmapsink_xpixmap_link(evaspixmapsink)) { + GST_ERROR_OBJECT (evaspixmapsink,"link evas image object with pixmap failed..."); + return; + } +#ifdef COMPARE_RATIO + } +#endif + } + + gst_evaspixmap_buffer_put (evaspixmapsink, evaspixmapsink->evas_pixmap_buf); + + GST_DEBUG_OBJECT (evaspixmapsink,"[END]"); +} + +static inline gboolean +is_evas_image_object (Evas_Object *obj) +{ + const char *type; + if (!obj) { + return FALSE; + } + type = evas_object_type_get (obj); + if (!type) { + return FALSE; + } + if (strcmp (type, "image") == 0) { + return TRUE; + } + return FALSE; +} + +static void +evas_callback_del_event (void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + GstEvasPixmapSink *evaspixmapsink = data; + if (!evaspixmapsink) { + GST_WARNING ("evaspixmapsink is NULL.."); + return; + } + GST_DEBUG_OBJECT (evaspixmapsink,"[START]"); + + evas_object_event_callback_del(evaspixmapsink->eo, EVAS_CALLBACK_RESIZE, evas_callback_resize_event); + if (evaspixmapsink->eo) { + evas_object_image_native_surface_set(evaspixmapsink->eo, NULL); + evaspixmapsink->eo = NULL; + } + + GST_DEBUG_OBJECT (evaspixmapsink,"[END]"); +} + +/* X11 stuff */ +static gboolean error_caught = FALSE; + +static int +gst_evaspixmapsink_handle_xerror (Display * display, XErrorEvent * xevent) +{ + char error_msg[1024]; + + XGetErrorText (display, xevent->error_code, error_msg, 1024); + GST_DEBUG ("evaspixmapsink triggered an XError. error: %s", error_msg); + error_caught = TRUE; + return 0; +} + +#ifdef DUMP_IMG +int util_write_rawdata(const char *file, const void *data, unsigned int size) +{ + FILE *fp; + + fp = fopen(file, "wb"); + if (fp == NULL) + { + GST_WARNING("fopen fail... size : %d", size); + return -1; + } + fwrite((char*)data, sizeof(char), size, fp); + fclose(fp); + + return 0; +} +#endif + +#ifdef HAVE_XSHM +/* This function checks that it is actually really possible to create an image + using XShm */ +static gboolean +gst_evaspixmapsink_check_xshm_calls (GstXContext * xcontext) +{ + XvImage *xvimage; + XShmSegmentInfo SHMInfo; + gint 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 (gst_evaspixmapsink_handle_xerror); + + /* Trying to create a 1x1 picture */ + GST_DEBUG ("XvShmCreateImage of 1x1"); + xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id, + xcontext->im_format, NULL, 1, 1, &SHMInfo); + + /* Might cause an error, sync to ensure it is noticed */ + XSync (xcontext->disp, FALSE); + if (!xvimage || error_caught) { + GST_WARNING ("could not XvShmCreateImage a 1x1 image"); + goto beach; + } + size = xvimage->data_size; + + SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777); + if (SHMInfo.shmid == -1) { + GST_WARNING ("could not get shared memory of %d bytes", size); + goto beach; + } + + SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0); + if (SHMInfo.shmaddr == ((void *) -1)) { + GST_WARNING ("Failed to shmat: %s", g_strerror (errno)); + /* Clean up the shared memory segment */ + shmctl (SHMInfo.shmid, IPC_RMID, NULL); + goto beach; + } + + xvimage->data = SHMInfo.shmaddr; + SHMInfo.readOnly = FALSE; + + if (XShmAttach (xcontext->disp, &SHMInfo) == 0) { + GST_WARNING ("Failed to XShmAttach"); + /* Clean up the shared memory segment */ + shmctl (SHMInfo.shmid, IPC_RMID, NULL); + goto beach; + } + + /* Sync to ensure we see any errors we caused */ + XSync (xcontext->disp, FALSE); + + /* Delete the shared memory segment as soon as everyone is attached. + * This way, it will be deleted as soon as we detach later, and not + * leaked if we crash. */ + shmctl (SHMInfo.shmid, IPC_RMID, NULL); + + if (!error_caught) { + GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid, + SHMInfo.shmseg); + + did_attach = TRUE; + /* store whether we succeeded in result */ + result = TRUE; + } else { + GST_WARNING ("MIT-SHM extension check failed at XShmAttach. " + "Not using shared memory."); + } + +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) { + GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx", + SHMInfo.shmid, SHMInfo.shmseg); + XShmDetach (xcontext->disp, &SHMInfo); + XSync (xcontext->disp, FALSE); + } + if (SHMInfo.shmaddr != ((void *) -1)) + shmdt (SHMInfo.shmaddr); + if (xvimage) + XFree (xvimage); + return result; +} +#endif /* HAVE_XSHM */ + +/* This function destroys a GstEvasPixmap handling XShm availability */ +static void +gst_evaspixmap_buffer_destroy (GstEvasPixmapBuffer *evaspixmapbuf) +{ + GstEvasPixmapSink *evaspixmapsink; + + GST_DEBUG_OBJECT (evaspixmapsink,"Destroying buffer"); + + evaspixmapsink = evaspixmapbuf->evaspixmapsink; + if (G_UNLIKELY (evaspixmapsink == NULL)) { + goto no_sink; + } + + g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink)); + + GST_OBJECT_LOCK (evaspixmapsink); + + /* We might have some buffers destroyed after changing state to NULL */ + if (evaspixmapsink->xcontext == NULL) { + GST_DEBUG_OBJECT (evaspixmapsink,"Destroying XvImage after Xcontext"); +#ifdef HAVE_XSHM + /* Need to free the shared memory segment even if the x context + * was already cleaned up */ + if (evaspixmapbuf->SHMInfo.shmaddr != ((void *) -1)) { + shmdt (evaspixmapbuf->SHMInfo.shmaddr); + } +#endif + goto beach; + } + g_mutex_lock (evaspixmapsink->x_lock); + +#ifdef HAVE_XSHM + if (evaspixmapsink->xcontext->use_xshm) { + if (evaspixmapbuf->SHMInfo.shmaddr != ((void *) -1)) { + GST_DEBUG_OBJECT (evaspixmapsink,"XServer ShmDetaching from 0x%x id 0x%lx", evaspixmapbuf->SHMInfo.shmid, evaspixmapbuf->SHMInfo.shmseg); + XShmDetach (evaspixmapsink->xcontext->disp, &evaspixmapbuf->SHMInfo); + XSync (evaspixmapsink->xcontext->disp, FALSE); + shmdt (evaspixmapbuf->SHMInfo.shmaddr); + } + if (evaspixmapbuf->xvimage) + XFree (evaspixmapbuf->xvimage); + } else +#endif /* HAVE_XSHM */ + { + if (evaspixmapbuf->xvimage) { + if (evaspixmapbuf->xvimage->data) { + g_free (evaspixmapbuf->xvimage->data); + } + XFree (evaspixmapbuf->xvimage); + } + } + + XSync (evaspixmapsink->xcontext->disp, FALSE); + + g_mutex_unlock (evaspixmapsink->x_lock); + +beach: + GST_OBJECT_UNLOCK (evaspixmapsink); + evaspixmapbuf->evaspixmapsink = NULL; + gst_object_unref (evaspixmapsink); + gst_buffer_unref(evaspixmapbuf->buffer); + free(evaspixmapbuf); + return; + + no_sink: + { + GST_WARNING_OBJECT (evaspixmapsink,"no sink found"); + return; + } +} + +static void +gst_evaspixmap_buffer_finalize (GstEvasPixmapBuffer *evaspixmapbuf) +{ + GstEvasPixmapSink *evaspixmapsink; + + evaspixmapsink = evaspixmapbuf->evaspixmapsink; + if (G_UNLIKELY (evaspixmapsink == NULL)) { + GST_WARNING_OBJECT (evaspixmapsink,"no sink found"); + return; + } + g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink)); + + /* If our geometry changed we can't reuse that image. */ + GST_LOG_OBJECT (evaspixmapsink,"destroy image as sink is shutting down"); + gst_evaspixmap_buffer_destroy (evaspixmapbuf); +} + +static void +gst_evaspixmap_buffer_free (GstEvasPixmapBuffer *evaspixmapbuf) +{ + /* make sure it is not recycled */ + evaspixmapbuf->width = -1; + evaspixmapbuf->height = -1; + g_boxed_free(GST_TYPE_EVASPIXMAP_BUFFER, evaspixmapbuf); +} + +static void +gst_evaspixmap_buffer_init (GstEvasPixmapBuffer *evaspixmapbuf, gpointer g_class) +{ +#ifdef HAVE_XSHM + evaspixmapbuf->SHMInfo.shmaddr = ((void *) -1); + evaspixmapbuf->SHMInfo.shmid = -1; +#endif +} + +static void +gst_evaspixmap_buffer_class_init (gpointer g_class, gpointer class_data) +{ +} + +/* This function handles GstEvasPixmapBuffer creation depending on XShm availability */ +static GstEvasPixmapBuffer* +gst_evaspixmap_buffer_new (GstEvasPixmapSink *evaspixmapsink, GstCaps *caps) +{ + GstEvasPixmapBuffer *evaspixmapbuf = NULL; + GstStructure *structure = NULL; + gboolean succeeded = FALSE; + int (*handler) (Display *, XErrorEvent *); + + g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), NULL); + + if (caps == NULL) { + return NULL; + } + + evaspixmapbuf = (GstEvasPixmapBuffer*) malloc (sizeof(GstEvasPixmapBuffer)); + GST_DEBUG_OBJECT (evaspixmapsink,"Creating new EvasPixmapBuffer"); + evaspixmapbuf->buffer = gst_buffer_new(); + + structure = gst_caps_get_structure (caps, 0); + + if (!gst_structure_get_int (structure, "width", &evaspixmapbuf->width) || !gst_structure_get_int (structure, "height", &evaspixmapbuf->height)) { + GST_WARNING_OBJECT (evaspixmapsink,"failed getting geometry from caps %" GST_PTR_FORMAT, caps); + } + + GST_LOG_OBJECT (evaspixmapsink,"creating %dx%d", evaspixmapbuf->width, evaspixmapbuf->height); +#ifdef GST_EXT_XV_ENHANCEMENT + GST_LOG_OBJECT (evaspixmapsink,"aligned size %dx%d", evaspixmapsink->aligned_width, evaspixmapsink->aligned_height); + if (evaspixmapsink->aligned_width == 0 || evaspixmapsink->aligned_height == 0) { + GST_INFO_OBJECT (evaspixmapsink,"aligned size is zero. set size of caps."); + evaspixmapsink->aligned_width = evaspixmapbuf->width; + evaspixmapsink->aligned_height = evaspixmapbuf->height; + } +#endif + + evaspixmapbuf->im_format = gst_evaspixmapsink_get_format_from_caps (evaspixmapsink, caps); + if (evaspixmapbuf->im_format == -1) { + GST_WARNING_OBJECT (evaspixmapsink,"failed to get format from caps %"GST_PTR_FORMAT, caps); + GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE,("Failed to create output image buffer of %dx%d pixels", + evaspixmapbuf->width, evaspixmapbuf->height), ("Invalid input caps")); + goto beach_unlocked; + } + evaspixmapbuf->evaspixmapsink = gst_object_ref (evaspixmapsink); + + g_mutex_lock (evaspixmapsink->x_lock); + + /* Setting an error handler to catch failure */ + error_caught = FALSE; + handler = XSetErrorHandler (gst_evaspixmapsink_handle_xerror); + +#ifdef HAVE_XSHM + if (evaspixmapsink->xcontext->use_xshm) { + int expected_size; + evaspixmapbuf->xvimage = XvShmCreateImage (evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, evaspixmapbuf->im_format, NULL, +#ifdef GST_EXT_XV_ENHANCEMENT + evaspixmapsink->aligned_width, evaspixmapsink->aligned_height, &evaspixmapbuf->SHMInfo); + if(!evaspixmapbuf->xvimage) { + GST_ERROR_OBJECT (evaspixmapsink,"XvShmCreateImage() failed"); + } +#else + evaspixmapbuf->width, evaspixmapbuf->height, &evaspixmapbuf->SHMInfo); +#endif + if (!evaspixmapbuf->xvimage || error_caught) { + if (error_caught) { + GST_ERROR_OBJECT (evaspixmapsink,"error_caught!"); + } + g_mutex_unlock (evaspixmapsink->x_lock); + /* Reset error handler */ + error_caught = FALSE; + XSetErrorHandler (handler); + /* Push an error */ + GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE,("Failed to create output image buffer of %dx%d pixels",evaspixmapbuf->width, + evaspixmapbuf->height),("could not XvShmCreateImage a %dx%d image",evaspixmapbuf->width, evaspixmapbuf->height)); + goto beach_unlocked; + } + + /* we have to use the returned data_size for our shm size */ + evaspixmapbuf->size = evaspixmapbuf->xvimage->data_size; + GST_LOG_OBJECT (evaspixmapsink,"XShm image size is %" G_GSIZE_FORMAT, evaspixmapbuf->size); + + /* calculate the expected size. This is only for sanity checking the + * number we get from X. */ + switch (evaspixmapbuf->im_format) { + case GST_MAKE_FOURCC ('I', '4', '2', '0'): + case GST_MAKE_FOURCC ('Y', 'V', '1', '2'): + { + gint pitches[3]; + gint offsets[3]; + guint plane; + + offsets[0] = 0; + pitches[0] = GST_ROUND_UP_4 (evaspixmapbuf->width); + offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (evaspixmapbuf->height); + pitches[1] = GST_ROUND_UP_8 (evaspixmapbuf->width) / 2; + offsets[2] = + offsets[1] + pitches[1] * GST_ROUND_UP_2 (evaspixmapbuf->height) / 2; + pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2; + + expected_size = offsets[2] + pitches[2] * GST_ROUND_UP_2 (evaspixmapbuf->height) / 2; + + for (plane = 0; plane < evaspixmapbuf->xvimage->num_planes; plane++) { + GST_DEBUG_OBJECT (evaspixmapsink,"Plane %u has a expected pitch of %d bytes, " "offset of %d", + plane, pitches[plane], offsets[plane]); + } + break; + } + case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'): + case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'): + expected_size = evaspixmapbuf->height * GST_ROUND_UP_4 (evaspixmapbuf->width * 2); + break; + + #ifdef GST_EXT_XV_ENHANCEMENT + case GST_MAKE_FOURCC ('S', 'T', '1', '2'): + case GST_MAKE_FOURCC ('S', 'N', '1', '2'): + case GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'): + case GST_MAKE_FOURCC ('S', 'U', 'Y', '2'): + case GST_MAKE_FOURCC ('S', '4', '2', '0'): + case GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y'): + expected_size = sizeof(SCMN_IMGB); + break; + #endif + default: + expected_size = 0; + break; + } + if (expected_size != 0 && evaspixmapbuf->size != expected_size) { + GST_WARNING_OBJECT (evaspixmapsink,"unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)", evaspixmapbuf->size, expected_size); + } + + /* Be verbose about our XvImage stride */ + { + guint plane; + for (plane = 0; plane < evaspixmapbuf->xvimage->num_planes; plane++) { + GST_DEBUG_OBJECT (evaspixmapsink,"Plane %u has a pitch of %d bytes, ""offset of %d", plane, + evaspixmapbuf->xvimage->pitches[plane], evaspixmapbuf->xvimage->offsets[plane]); + } + } + + evaspixmapbuf->SHMInfo.shmid = shmget (IPC_PRIVATE, evaspixmapbuf->size,IPC_CREAT | 0777); + if (evaspixmapbuf->SHMInfo.shmid == -1) { + g_mutex_unlock (evaspixmapsink->x_lock); + GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE, + ("Failed to create output image buffer of %dx%d pixels", evaspixmapbuf->width, evaspixmapbuf->height), + ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",evaspixmapbuf->size)); + goto beach_unlocked; + } + + evaspixmapbuf->SHMInfo.shmaddr = shmat (evaspixmapbuf->SHMInfo.shmid, NULL, 0); + if (evaspixmapbuf->SHMInfo.shmaddr == ((void *) -1)) { + g_mutex_unlock (evaspixmapsink->x_lock); + GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE, + ("Failed to create output image buffer of %dx%d pixels", + evaspixmapbuf->width, evaspixmapbuf->height), + ("Failed to shmat: %s", g_strerror (errno))); + /* Clean up the shared memory segment */ + shmctl (evaspixmapbuf->SHMInfo.shmid, IPC_RMID, NULL); + goto beach_unlocked; + } + + evaspixmapbuf->xvimage->data = evaspixmapbuf->SHMInfo.shmaddr; + evaspixmapbuf->SHMInfo.readOnly = FALSE; + + if (XShmAttach (evaspixmapsink->xcontext->disp, &evaspixmapbuf->SHMInfo) == 0) { + /* Clean up the shared memory segment */ + shmctl (evaspixmapbuf->SHMInfo.shmid, IPC_RMID, NULL); + + g_mutex_unlock (evaspixmapsink->x_lock); + GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE, + ("Failed to create output image buffer of %dx%d pixels", + evaspixmapbuf->width, evaspixmapbuf->height), ("Failed to XShmAttach")); + goto beach_unlocked; + } + + XSync (evaspixmapsink->xcontext->disp, FALSE); + + /* Delete the shared memory segment as soon as we everyone is attached. + * This way, it will be deleted as soon as we detach later, and not + * leaked if we crash. */ + shmctl (evaspixmapbuf->SHMInfo.shmid, IPC_RMID, NULL); + + GST_DEBUG_OBJECT (evaspixmapsink,"XServer ShmAttached to 0x%x, id 0x%lx", evaspixmapbuf->SHMInfo.shmid, evaspixmapbuf->SHMInfo.shmseg); + } else +#endif /* HAVE_XSHM */ + { + evaspixmapbuf->xvimage = XvCreateImage (evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, +#ifdef GST_EXT_XV_ENHANCEMENT + evaspixmapbuf->im_format, NULL, evaspixmapsink->aligned_width, evaspixmapsink->aligned_height); +#else + evaspixmapbuf->im_format, NULL, evaspixmapbuf->width, evaspixmapbuf->height); +#endif + if (!evaspixmapbuf->xvimage || error_caught) { + g_mutex_unlock (evaspixmapsink->x_lock); + /* Reset error handler */ + error_caught = FALSE; + XSetErrorHandler (handler); + /* Push an error */ + GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE, + ("Failed to create outputimage buffer of %dx%d pixels", + evaspixmapbuf->width, evaspixmapbuf->height), + ("could not XvCreateImage a %dx%d image", + evaspixmapbuf->width, evaspixmapbuf->height)); + goto beach_unlocked; + } + + /* we have to use the returned data_size for our image size */ + evaspixmapbuf->size = evaspixmapbuf->xvimage->data_size; + evaspixmapbuf->xvimage->data = g_malloc (evaspixmapbuf->size); + + XSync (evaspixmapsink->xcontext->disp, FALSE); + } + + /* Reset error handler */ + error_caught = FALSE; + XSetErrorHandler (handler); + + succeeded = TRUE; + + gst_buffer_replace_all_memory(evaspixmapbuf->buffer, gst_memory_new_wrapped(GST_MEMORY_FLAG_READONLY, + (guchar *) evaspixmapbuf->xvimage->data, + evaspixmapbuf->size, + 0, + evaspixmapbuf->size, + NULL, NULL)); + g_mutex_unlock (evaspixmapsink->x_lock); + +beach_unlocked: + if (!succeeded) { + gst_evaspixmap_buffer_free (evaspixmapbuf); + evaspixmapbuf = NULL; + } + + return evaspixmapbuf; +} + +/* This function puts a GstEvasPixmapBuffer on a GstEvasPixmapSink's pixmap. Returns FALSE + * if no pixmap was available */ +static gboolean +gst_evaspixmap_buffer_put (GstEvasPixmapSink *evaspixmapsink, GstEvasPixmapBuffer *evaspixmapbuf) +{ + GstVideoRectangle result; + +#ifdef GST_EXT_XV_ENHANCEMENT + GstVideoRectangle src_origin = { 0, 0, 0, 0}; + GstVideoRectangle src_input = { 0, 0, 0, 0}; + GstVideoRectangle src = { 0, 0, 0, 0}; + GstVideoRectangle dst = { 0, 0, 0, 0}; + int rotate = 0; + int ret = 0; +#endif + + /* We take the flow_lock. If expose is in there we don't want to run + concurrently from the data flow thread */ + g_mutex_lock (evaspixmapsink->flow_lock); + + if (G_UNLIKELY (evaspixmapsink->xpixmap == NULL)) { + GST_WARNING_OBJECT (evaspixmapsink, "xpixmap is NULL. Skip buffer_put." ); + g_mutex_unlock(evaspixmapsink->flow_lock); + return FALSE; + } + if (evaspixmapsink->visible == FALSE) { + GST_WARNING_OBJECT (evaspixmapsink, "visible is FALSE. Skip buffer_put." ); + g_mutex_unlock(evaspixmapsink->flow_lock); + return TRUE; + } + if (!evaspixmapbuf) { + GST_WARNING_OBJECT (evaspixmapsink, "evaspixmapbuf is NULL. Skip buffer_put." ); + g_mutex_unlock(evaspixmapsink->flow_lock); + return TRUE; + } + +#ifdef GST_EXT_XV_ENHANCEMENT + gst_evaspixmapsink_xpixmap_update_geometry( evaspixmapsink ); + + src.x = src.y = 0; + src_origin.x = src_origin.y = src_input.x = src_input.y = 0; + src_input.w = src_origin.w = evaspixmapsink->video_width; + src_input.h = src_origin.h = evaspixmapsink->video_height; + src.w = src_origin.w; + src.h = src_origin.h; + + dst.w = evaspixmapsink->render_rect.w; /* pixmap width */ + dst.h = evaspixmapsink->render_rect.h; /* pixmap heighy */ + + if (!evaspixmapsink->use_origin_size) { + switch (evaspixmapsink->display_geometry_method) { + case DISP_GEO_METHOD_LETTER_BOX: + gst_video_sink_center_rect (src, dst, &result, TRUE); + result.x += evaspixmapsink->render_rect.x; + result.y += evaspixmapsink->render_rect.y; + GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : letter box"); + break; + case DISP_GEO_METHOD_ORIGIN_SIZE: + gst_video_sink_center_rect (src, dst, &result, FALSE); + gst_video_sink_center_rect (dst, src, &src_input, FALSE); + GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : origin size"); + break; + case DISP_GEO_METHOD_CROPPED_FULL_SCREEN: + GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : cropped full screen"); + gst_video_sink_center_rect(dst, src, &src_input, TRUE); + result.x = result.y = 0; + result.w = dst.w; + result.h = dst.h; + break; + case DISP_GEO_METHOD_FULL_SCREEN: + result.x = result.y = 0; + result.w = evaspixmapsink->xpixmap->width; + result.h = evaspixmapsink->xpixmap->height; + GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : full screen"); + break; + case DISP_GEO_METHOD_CUSTOM_ROI: + result.x = evaspixmapsink->dst_roi.x; + result.y = evaspixmapsink->dst_roi.y; + result.w = evaspixmapsink->dst_roi.w; + result.h = evaspixmapsink->dst_roi.h; + GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : custom roi"); + break; + default: + break; + } + GST_DEBUG_OBJECT (evaspixmapsink, "GEO_METHOD : src(%dx%d), dst(%dx%d), result(%dx%d), result_x(%d), result_y(%d)", + src.w,src.h,dst.w,dst.h,result.w,result.h,result.x,result.y); + } else { + result.x = result.y = 0; + result.w = evaspixmapsink->xpixmap->width; + result.h = evaspixmapsink->xpixmap->height; + GST_DEBUG_OBJECT (evaspixmapsink, "USE ORIGIN SIZE, no geometry method" ); + } +#else + if (evaspixmapsink->keep_aspect) { + GstVideoRectangle src, dst; + /* We use the calculated geometry from _setcaps as a source to respect + source and screen pixel aspect ratios. */ + src.w = GST_VIDEO_SINK_WIDTH (evaspixmapsink); + src.h = GST_VIDEO_SINK_HEIGHT (evaspixmapsink); + dst.w = evaspixmapsink->render_rect.w; + dst.h = evaspixmapsink->render_rect.h; + + gst_video_sink_center_rect (src, dst, &result, TRUE); + result.x += evaspixmapsink->render_rect.x; + result.y += evaspixmapsink->render_rect.y; + } else { + memcpy (&result, &evaspixmapsink->render_rect, sizeof (GstVideoRectangle)); + } +#endif + + g_mutex_lock (evaspixmapsink->x_lock); + + /* We scale to the pixmap's geometry */ +#ifdef HAVE_XSHM + if (evaspixmapsink->xcontext->use_xshm) { + GST_LOG_OBJECT (evaspixmapsink,"XvShmPutImage with image %dx%d and pixmap %dx%d, from xvimage %" + GST_PTR_FORMAT, + evaspixmapbuf->width, evaspixmapbuf->height, + evaspixmapsink->render_rect.w, evaspixmapsink->render_rect.h, evaspixmapbuf); + +#ifdef GST_EXT_XV_ENHANCEMENT + /* Trim as proper size */ + if (src_input.w % 2 == 1) { + src_input.w += 1; + } + if (src_input.h % 2 == 1) { + src_input.h += 1; + } + + GST_LOG_OBJECT (evaspixmapsink, "screen[%dx%d],pixmap[%d,%d,%dx%d],method[%d],rotate[%d],src[%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]", + evaspixmapsink->scr_w, evaspixmapsink->scr_h, + evaspixmapsink->xpixmap->x, evaspixmapsink->xpixmap->y, evaspixmapsink->xpixmap->width, evaspixmapsink->xpixmap->height, + evaspixmapsink->display_geometry_method, rotate, + src_origin.w, src_origin.h, + dst.x, dst.y, dst.w, dst.h, + src_input.x, src_input.y, src_input.w, src_input.h, + result.x, result.y, result.w, result.h ); + + if (evaspixmapsink->visible) { + ret = XvShmPutImage (evaspixmapsink->xcontext->disp, + evaspixmapsink->xcontext->xv_port_id, + evaspixmapsink->xpixmap->pixmap, + evaspixmapsink->xpixmap->gc, evaspixmapbuf->xvimage, + src_input.x, src_input.y, src_input.w, src_input.h, + result.x, result.y, result.w, result.h, FALSE); + GST_LOG_OBJECT (evaspixmapsink, "XvShmPutImage return value [%d]", ret ); +#ifdef DUMP_IMG + int ret = 0; + char file_name[128]; + int dump_size = evaspixmapbuf->xvimage->data_size; + + if(g_cnt<10) { + GST_INFO ("DUMP IMG_%2.2d : buffer size(%d)", g_cnt, dump_size); + sprintf(file_name, "/opt/usr/media/DUMP_IMG_%2.2d.dump", g_cnt); + ret = util_write_rawdata(file_name, evaspixmapbuf->xvimage->data, dump_size); + if (ret) { + GST_ERROR_OBJECT (evaspixmapsink, "util_write_rawdata() failed"); + } else + g_cnt++; + } +#endif + } else { + GST_WARNING_OBJECT (evaspixmapsink, "visible is FALSE. skip this image..." ); + } +#else /* GST_EXT_XV_ENHANCEMENT */ + if (evaspixmapsink->visible) { + XvShmPutImage (evaspixmapsink->xcontext->disp, + evaspixmapsink->xcontext->xv_port_id, + evaspixmapsink->xpixmap->pixmap, + evaspixmapsink->xpixmap->gc, evaspixmapbuf->xvimage, + evaspixmapsink->disp_x, evaspixmapsink->disp_y, + evaspixmapsink->disp_width, evaspixmapsink->disp_height, + result.x, result.y, result.w, result.h, FALSE); + } else { + GST_WARNING_OBJECT (evaspixmapsink, "visible is FALSE. skip this image..." ); + } +#endif /* GST_EXT_XV_ENHANCEMENT */ + } else +#endif /* HAVE_XSHM */ + { + if (evaspixmapsink->visible) { + XvPutImage (evaspixmapsink->xcontext->disp, + evaspixmapsink->xcontext->xv_port_id, + evaspixmapsink->xpixmap->pixmap, + evaspixmapsink->xpixmap->gc, evaspixmapbuf->xvimage, + evaspixmapsink->disp_x, evaspixmapsink->disp_y, + evaspixmapsink->disp_width, evaspixmapsink->disp_height, + result.x, result.y, result.w, result.h); + } else { + GST_WARNING_OBJECT (evaspixmapsink, "visible is FALSE. skip this image..." ); + } + } + XSync (evaspixmapsink->xcontext->disp, FALSE); + + g_mutex_unlock (evaspixmapsink->x_lock); + g_mutex_unlock (evaspixmapsink->flow_lock); + + + return TRUE; +} + +static int +drm_init(GstEvasPixmapSink *evaspixmapsink) +{ + Display *dpy; + int i = 0; + int eventBase = 0; + int errorBase = 0; + int dri2Major = 0; + int dri2Minor = 0; + char *driverName = NULL; + char *deviceName = NULL; + struct drm_auth auth_arg = {0}; + + evaspixmapsink->drm_fd = -1; + + dpy = XOpenDisplay(0); + + /* DRI2 */ + if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) { + GST_ERROR_OBJECT (evaspixmapsink,"failed to DRI2QueryExtension()"); + goto ERROR_CASE; + } + + if (!DRI2QueryVersion(dpy, &dri2Major, &dri2Minor)) { + GST_ERROR_OBJECT (evaspixmapsink,"failed to DRI2QueryVersion"); + goto ERROR_CASE; + } + + if (!DRI2Connect(dpy, RootWindow(dpy, DefaultScreen(dpy)), &driverName, &deviceName)) { + GST_ERROR_OBJECT (evaspixmapsink,"failed to DRI2Connect"); + goto ERROR_CASE; + } + + if (!driverName || !deviceName) { + GST_ERROR_OBJECT (evaspixmapsink,"driverName or deviceName is not valid"); + goto ERROR_CASE; + } + + GST_INFO_OBJECT (evaspixmapsink,"Open drm device : %s", deviceName); + + /* get the drm_fd though opening the deviceName */ + evaspixmapsink->drm_fd = open(deviceName, O_RDWR); + if (evaspixmapsink->drm_fd < 0) { + GST_ERROR_OBJECT (evaspixmapsink,"cannot open drm device (%s)", deviceName); + goto ERROR_CASE; + } + + /* get magic from drm to authentication */ + if (ioctl(evaspixmapsink->drm_fd, DRM_IOCTL_GET_MAGIC, &auth_arg)) { + GST_ERROR_OBJECT (evaspixmapsink,"cannot get drm auth magic"); + close(evaspixmapsink->drm_fd); + evaspixmapsink->drm_fd = -1; + goto ERROR_CASE; + } + + if (!DRI2Authenticate(dpy, RootWindow(dpy, DefaultScreen(dpy)), auth_arg.magic)) { + GST_ERROR_OBJECT (evaspixmapsink,"cannot get drm authentication from X"); + close(evaspixmapsink->drm_fd); + evaspixmapsink->drm_fd = -1; + goto ERROR_CASE; + } + + /* init gem handle */ + for (i = 0; i < MAX_GEM_BUFFER_NUM; i++) { + evaspixmapsink->gem_info[i].dmabuf_fd = 0; + evaspixmapsink->gem_info[i].gem_handle = 0; + evaspixmapsink->gem_info[i].gem_name = 0; + } + + XCloseDisplay(dpy); + free(driverName); + free(deviceName); + + return 0; + +ERROR_CASE: + XCloseDisplay(dpy); + if (driverName) { + free(driverName); + } + if (deviceName) { + free(deviceName); + } + + return -1; +} + +static void +drm_fini(GstEvasPixmapSink *evaspixmapsink) +{ + if (evaspixmapsink->drm_fd >= 0) { + int i = 0; + for (i = 0; i < MAX_GEM_BUFFER_NUM; i++) { + if (evaspixmapsink->gem_info[i].dmabuf_fd > 0) { + GST_INFO_OBJECT (evaspixmapsink,"close gem_handle(%u)", evaspixmapsink->gem_info[i].gem_handle); + drm_close_gem(evaspixmapsink, evaspixmapsink->gem_info[i].gem_handle); + + evaspixmapsink->gem_info[i].dmabuf_fd = 0; + evaspixmapsink->gem_info[i].gem_handle = 0; + evaspixmapsink->gem_info[i].gem_name = 0; + } else { + break; + } + } + GST_INFO_OBJECT (evaspixmapsink,"close drm_fd(%d)", evaspixmapsink->drm_fd); + close(evaspixmapsink->drm_fd); + evaspixmapsink->drm_fd = -1; + } +} + +static unsigned int +drm_convert_dmabuf_gemname(GstEvasPixmapSink *evaspixmapsink, int dmabuf_fd) +{ + struct drm_prime_handle prime_arg = {0,}; + struct drm_gem_flink flink_arg = {0,}; + int i = 0; + + if (evaspixmapsink->drm_fd < 0) { + GST_ERROR_OBJECT (evaspixmapsink,"DRM is not opened"); + return 0; + } + + if (dmabuf_fd <= 0) { + GST_DEBUG_OBJECT (evaspixmapsink,"Ignore wrong dmabuf fd(%d)", dmabuf_fd); /* temporarily change log level to DEBUG for reducing WARNING level log */ + return 0; + } + + /* check duplicated dmabuf fd */ + for (i = 0 ; i < MAX_GEM_BUFFER_NUM ; i++) { + if (evaspixmapsink->gem_info[i].dmabuf_fd == dmabuf_fd) { + GST_LOG_OBJECT (evaspixmapsink,"already got fd(%u) with name(%u)", dmabuf_fd, evaspixmapsink->gem_info[i].gem_name); + return evaspixmapsink->gem_info[i].gem_name; + } + + if (evaspixmapsink->gem_info[i].dmabuf_fd == 0) { + GST_LOG_OBJECT (evaspixmapsink,"empty gem_info[%d] found", i); + break; + } + } + + if (i == MAX_GEM_BUFFER_NUM) { + GST_WARNING_OBJECT (evaspixmapsink,"too many buffers[dmabuf_fd(%d). skip it]", dmabuf_fd); + return 0; + } + + evaspixmapsink->gem_info[i].dmabuf_fd = dmabuf_fd; + prime_arg.fd = dmabuf_fd; + if (ioctl(evaspixmapsink->drm_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime_arg)) { + GST_ERROR_OBJECT (evaspixmapsink,"non dmabuf fd(%d)", dmabuf_fd); + return 0; + } + + evaspixmapsink->gem_info[i].gem_handle = prime_arg.handle; + GST_LOG_OBJECT (evaspixmapsink,"gem_info[%d].gem_handle = %u", i, prime_arg.handle); + + flink_arg.handle = prime_arg.handle; + if (ioctl(evaspixmapsink->drm_fd, DRM_IOCTL_GEM_FLINK, &flink_arg)) { + GST_ERROR_OBJECT (evaspixmapsink,"cannot convert drm handle to name"); + return 0; + } + + evaspixmapsink->gem_info[i].gem_name = flink_arg.name; + GST_LOG_OBJECT (evaspixmapsink,"gem_info[%d].gem_name = %u", i, flink_arg.name); + + return flink_arg.name; +} + +static void +drm_close_gem(GstEvasPixmapSink *evaspixmapsink, unsigned int gem_handle) +{ + struct drm_gem_close close_arg = {0,}; + + if (evaspixmapsink->drm_fd < 0) { + GST_ERROR_OBJECT (evaspixmapsink,"DRM is not opened"); + return; + } + + if (gem_handle == 0) { + GST_ERROR_OBJECT (evaspixmapsink,"invalid gem_handle(%d)",gem_handle); + return; + } + + close_arg.handle = gem_handle; + if (gem_handle > 0 && ioctl(evaspixmapsink->drm_fd, DRM_IOCTL_GEM_CLOSE, &close_arg)) { + GST_ERROR_OBJECT (evaspixmapsink,"cannot close drm gem handle(%d)", gem_handle); + return; + } + + return; +} + +G_DEFINE_TYPE_EXTENDED(GstEvasPixmapSink, gst_evaspixmapsink, GST_TYPE_VIDEO_SINK, 0, + G_IMPLEMENT_INTERFACE(GST_TYPE_NAVIGATION, gst_evaspixmapsink_navigation_init) + G_IMPLEMENT_INTERFACE(GST_TYPE_COLOR_BALANCE, gst_evaspixmapsink_colorbalance_init) + G_IMPLEMENT_INTERFACE(GST_TYPE_PROPERTY_PROBE, gst_evaspixmapsink_property_probe_interface_init)); + + +/* This function destroys a GstXPixmap */ +static void +gst_evaspixmapsink_xpixmap_destroy (GstEvasPixmapSink *evaspixmapsink, GstXPixmap *xpixmap) +{ + g_return_if_fail (xpixmap != NULL); + g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink)); + + g_mutex_lock (evaspixmapsink->x_lock); + + if(evaspixmapsink->xpixmap->pixmap) { + XFreePixmap(evaspixmapsink->xcontext->disp, evaspixmapsink->xpixmap->pixmap); + evaspixmapsink->xpixmap->pixmap = NULL; + GST_DEBUG_OBJECT (evaspixmapsink,"Free pixmap"); + } + + if (xpixmap->gc) { + XFreeGC (evaspixmapsink->xcontext->disp, xpixmap->gc); + } + + XSync (evaspixmapsink->xcontext->disp, FALSE); + + g_mutex_unlock (evaspixmapsink->x_lock); + + g_free (xpixmap); +} + +static void +gst_evaspixmapsink_xpixmap_update_geometry (GstEvasPixmapSink *evaspixmapsink) +{ +#ifdef GST_EXT_XV_ENHANCEMENT + Window root_window; + XWindowAttributes root_attr; + + int cur_pixmap_x = 0; + int cur_pixmap_y = 0; + unsigned int cur_pixmap_width = 0; + unsigned int cur_pixmap_height = 0; + unsigned int cur_pixmap_border_width = 0; + unsigned int cur_pixmap_depth = 0; +#else + XWindowAttributes attr; +#endif + g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink)); + + /* Update the window geometry */ + g_mutex_lock (evaspixmapsink->x_lock); + if (G_UNLIKELY (evaspixmapsink->xpixmap == NULL)) { + g_mutex_unlock (evaspixmapsink->x_lock); + return; + } + +#ifdef GST_EXT_XV_ENHANCEMENT + /* Get root window and size of current pixmap */ + XGetGeometry( evaspixmapsink->xcontext->disp, evaspixmapsink->xpixmap->pixmap, &root_window, + &cur_pixmap_x, &cur_pixmap_y, /* relative x, y, for pixmap these are alway 0 */ + &cur_pixmap_width, &cur_pixmap_height, + &cur_pixmap_border_width, &cur_pixmap_depth ); /* cur_pixmap_border_width, cur_pixmap_depth are not used */ + + evaspixmapsink->xpixmap->width = cur_pixmap_width; + evaspixmapsink->xpixmap->height = cur_pixmap_height; + + evaspixmapsink->xpixmap->x = cur_pixmap_x; + evaspixmapsink->xpixmap->y = cur_pixmap_y; + + /* Get size of root window == size of screen */ + XGetWindowAttributes(evaspixmapsink->xcontext->disp, root_window, &root_attr); + + evaspixmapsink->scr_w = root_attr.width; + evaspixmapsink->scr_h = root_attr.height; + + if (!evaspixmapsink->have_render_rect) { + evaspixmapsink->render_rect.x = evaspixmapsink->render_rect.y = 0; + evaspixmapsink->render_rect.w = cur_pixmap_width; + evaspixmapsink->render_rect.h = cur_pixmap_height; + } + + GST_LOG_OBJECT (evaspixmapsink,"screen size %dx%d, current pixmap geometry %d,%d,%dx%d, render_rect %d,%d,%dx%d", + evaspixmapsink->scr_w, evaspixmapsink->scr_h, + evaspixmapsink->xpixmap->x, evaspixmapsink->xpixmap->y, + evaspixmapsink->xpixmap->width, evaspixmapsink->xpixmap->height, + evaspixmapsink->render_rect.x, evaspixmapsink->render_rect.y, + evaspixmapsink->render_rect.w, evaspixmapsink->render_rect.h); +#else + XGetWindowAttributes (evaspixmapsink->xcontext->disp, evaspixmapsink->xpixmap->pixmap, &attr); + + evaspixmapsink->xpixmap->width = attr.width; + evaspixmapsink->xpixmap->height = attr.height; + + if (!evaspixmapsink->have_render_rect) { + evaspixmapsink->render_rect.x = evaspixmapsink->render_rect.y = 0; + evaspixmapsink->render_rect.w = attr.width; + evaspixmapsink->render_rect.h = attr.height; + } +#endif + g_mutex_unlock (evaspixmapsink->x_lock); +} + +static void +gst_evaspixmapsink_xpixmap_clear (GstEvasPixmapSink *evaspixmapsink, GstXPixmap *xpixmap) +{ + g_return_if_fail (xpixmap != NULL); + g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink)); + + if (!xpixmap->pixmap) { + GST_WARNING_OBJECT (evaspixmapsink,"pixmap was not created.."); + return; + } + + g_mutex_lock (evaspixmapsink->x_lock); + + if( evaspixmapsink->stop_video ) { + XvStopVideo (evaspixmapsink->xcontext->disp, evaspixmapsink->xcontext->xv_port_id, xpixmap->pixmap); + } + /* Preview area is not updated before other UI is updated in the screen. */ + XSetForeground (evaspixmapsink->xcontext->disp, xpixmap->gc, evaspixmapsink->xcontext->black); + XFillRectangle (evaspixmapsink->xcontext->disp, xpixmap->pixmap, xpixmap->gc, + evaspixmapsink->render_rect.x, evaspixmapsink->render_rect.y, evaspixmapsink->render_rect.w, evaspixmapsink->render_rect.h); + + XSync (evaspixmapsink->xcontext->disp, FALSE); + + g_mutex_unlock (evaspixmapsink->x_lock); +} + +/* This function commits our internal colorbalance settings to our grabbed Xv + port. If the xcontext is not initialized yet it simply returns */ +static void +gst_evaspixmapsink_update_colorbalance (GstEvasPixmapSink *evaspixmapsink) +{ + GList *channels = NULL; + + g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink)); + + /* If we haven't initialized the X context we can't update anything */ + if (evaspixmapsink->xcontext == NULL) + return; + + /* Don't set the attributes if they haven't been changed, to avoid + * rounding errors changing the values */ + if (!evaspixmapsink->cb_changed) + return; + + /* For each channel of the colorbalance we calculate the correct value + doing range conversion and then set the Xv port attribute to match our + values. */ + channels = evaspixmapsink->xcontext->channels_list; + + while (channels) { + if (channels->data && GST_IS_COLOR_BALANCE_CHANNEL (channels->data)) { + GstColorBalanceChannel *channel = NULL; + Atom prop_atom; + gint value = 0; + gdouble convert_coef; + + channel = GST_COLOR_BALANCE_CHANNEL (channels->data); + g_object_ref (channel); + + /* Our range conversion coef */ + convert_coef = (channel->max_value - channel->min_value) / 2000.0; + + if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) { + value = evaspixmapsink->hue; + } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) { + value = evaspixmapsink->saturation; + } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) { + value = evaspixmapsink->contrast; + } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) { + value = evaspixmapsink->brightness; + } else { + g_warning ("got an unknown channel %s", channel->label); + g_object_unref (channel); + return; + } + + /* Committing to Xv port */ + g_mutex_lock (evaspixmapsink->x_lock); + prop_atom = + XInternAtom (evaspixmapsink->xcontext->disp, channel->label, True); + if (prop_atom != None) { + int xv_value; + xv_value = + floor (0.5 + (value + 1000) * convert_coef + channel->min_value); + XvSetPortAttribute (evaspixmapsink->xcontext->disp, + evaspixmapsink->xcontext->xv_port_id, prop_atom, xv_value); + } + g_mutex_unlock (evaspixmapsink->x_lock); + + g_object_unref (channel); + } + channels = g_list_next (channels); + } +} + +static void +gst_lookup_xv_port_from_adaptor (GstXContext *xcontext, XvAdaptorInfo *adaptors, int adaptor_no) +{ + gint j; + gint res; + + /* Do we support XvImageMask ? */ + if (!(adaptors[adaptor_no].type & XvImageMask)) { + GST_DEBUG ("XV Adaptor %s has no support for XvImageMask", adaptors[adaptor_no].name); + return; + } + + /* We found such an adaptor, looking for an available port */ + for (j = 0; j < adaptors[adaptor_no].num_ports && !xcontext->xv_port_id; j++) { + /* We try to grab the port */ + res = XvGrabPort (xcontext->disp, adaptors[adaptor_no].base_id + j, 0); + if (Success == res) { + xcontext->xv_port_id = adaptors[adaptor_no].base_id + j; + GST_DEBUG ("XV Adaptor %s with %ld ports", adaptors[adaptor_no].name, adaptors[adaptor_no].num_ports); + } else { + GST_DEBUG ("GrabPort %d for XV Adaptor %s failed: %d", j, adaptors[adaptor_no].name, res); + } + } +} + +/* This function generates a caps with all supported format by the first + Xv grabable port we find. We store each one of the supported formats in a + format list and append the format to a newly created caps that we return + If this function does not return NULL because of an error, it also grabs + the port via XvGrabPort */ +static GstCaps* +gst_evaspixmapsink_get_xv_support (GstEvasPixmapSink *evaspixmapsink, GstXContext *xcontext) +{ + gint i; + XvAdaptorInfo *adaptors; + gint nb_formats; + XvImageFormatValues *formats = NULL; + guint nb_encodings; + XvEncodingInfo *encodings = NULL; + gulong max_w = G_MAXINT, max_h = G_MAXINT; + GstCaps *caps = NULL; + GstCaps *rgb_caps = NULL; + + g_return_val_if_fail (xcontext != NULL, NULL); + + /* First let's check that XVideo extension is available */ + if (!XQueryExtension (xcontext->disp, "XVideo", &i, &i, &i)) { + GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, SETTINGS, + ("Could not initialise Xv output"), + ("XVideo extension is not available")); + return NULL; + } + + /* Then we get adaptors list */ + if (Success != XvQueryAdaptors (xcontext->disp, xcontext->root, + &xcontext->nb_adaptors, &adaptors)) { + GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, SETTINGS, + ("Could not initialise Xv output"), + ("Failed getting XV adaptors list")); + return NULL; + } + + xcontext->xv_port_id = 0; + + GST_DEBUG_OBJECT (evaspixmapsink,"Found %u XV adaptor(s)", xcontext->nb_adaptors); + + xcontext->adaptors = + (gchar **) g_malloc0 (xcontext->nb_adaptors * sizeof (gchar *)); + + /* Now fill up our adaptor name array */ + for (i = 0; i < xcontext->nb_adaptors; i++) { + xcontext->adaptors[i] = g_strdup (adaptors[i].name); + } + + if (evaspixmapsink->adaptor_no < xcontext->nb_adaptors) { + /* Find xv port from user defined adaptor */ + gst_lookup_xv_port_from_adaptor (xcontext, adaptors, evaspixmapsink->adaptor_no); + } + + if (!xcontext->xv_port_id) { + /* Now search for an adaptor that supports XvImageMask */ + for (i = 0; i < xcontext->nb_adaptors && !xcontext->xv_port_id; i++) { + gst_lookup_xv_port_from_adaptor (xcontext, adaptors, i); + evaspixmapsink->adaptor_no = i; + } + } + + XvFreeAdaptorInfo (adaptors); + + if (!xcontext->xv_port_id) { + evaspixmapsink->adaptor_no = -1; + GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, BUSY, + ("Could not initialise Xv output"), ("No port available")); + return NULL; + } + + /* Set XV_AUTOPAINT_COLORKEY and XV_DOUBLE_BUFFER and XV_COLORKEY */ + { + int count, todo = 3; + XvAttribute *const attr = XvQueryPortAttributes (xcontext->disp, + xcontext->xv_port_id, &count); + static const char autopaint[] = "XV_AUTOPAINT_COLORKEY"; + static const char dbl_buffer[] = "XV_DOUBLE_BUFFER"; + static const char colorkey[] = "XV_COLORKEY"; + + GST_DEBUG_OBJECT (evaspixmapsink,"Checking %d Xv port attributes", count); + + evaspixmapsink->have_autopaint_colorkey = FALSE; + evaspixmapsink->have_double_buffer = FALSE; + evaspixmapsink->have_colorkey = FALSE; + + for (i = 0; ((i < count) && todo); i++) + if (!strcmp (attr[i].name, autopaint)) { + const Atom atom = XInternAtom (xcontext->disp, autopaint, False); + + /* turn on autopaint colorkey */ + XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom, + (evaspixmapsink->autopaint_colorkey ? 1 : 0)); + todo--; + evaspixmapsink->have_autopaint_colorkey = TRUE; + } else if (!strcmp (attr[i].name, dbl_buffer)) { + const Atom atom = XInternAtom (xcontext->disp, dbl_buffer, False); + + XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom, + (evaspixmapsink->double_buffer ? 1 : 0)); + todo--; + evaspixmapsink->have_double_buffer = TRUE; + } else if (!strcmp (attr[i].name, colorkey)) { + /* Set the colorkey, default is something that is dark but hopefully + * won't randomly appear on the screen elsewhere (ie not black or greys) + * can be overridden by setting "colorkey" property + */ + const Atom atom = XInternAtom (xcontext->disp, colorkey, False); + guint32 ckey = 0; + gboolean set_attr = TRUE; + guint cr, cg, cb; + + /* set a colorkey in the right format RGB565/RGB888 + * We only handle these 2 cases, because they're the only types of + * devices we've encountered. If we don't recognise it, leave it alone + */ + cr = (evaspixmapsink->colorkey >> 16); + cg = (evaspixmapsink->colorkey >> 8) & 0xFF; + cb = (evaspixmapsink->colorkey) & 0xFF; + switch (xcontext->depth) { + case 16: /* RGB 565 */ + cr >>= 3; + cg >>= 2; + cb >>= 3; + ckey = (cr << 11) | (cg << 5) | cb; + break; + case 24: + case 32: /* RGB 888 / ARGB 8888 */ + ckey = (cr << 16) | (cg << 8) | cb; + break; + default: + GST_DEBUG_OBJECT (evaspixmapsink,"Unknown bit depth %d for Xv Colorkey - not adjusting", xcontext->depth); + set_attr = FALSE; + break; + } + + if (set_attr) { + ckey = CLAMP (ckey, (guint32) attr[i].min_value, + (guint32) attr[i].max_value); + GST_LOG_OBJECT (evaspixmapsink,"Setting color key for display depth %d to 0x%x", xcontext->depth, ckey); + + XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom, + (gint) ckey); + } + todo--; + evaspixmapsink->have_colorkey = TRUE; + } + + XFree (attr); + } + + /* Get the list of encodings supported by the adapter and look for the + * XV_IMAGE encoding so we can determine the maximum width and height + * supported */ + XvQueryEncodings (xcontext->disp, xcontext->xv_port_id, &nb_encodings, + &encodings); + + for (i = 0; i < nb_encodings; i++) { + GST_LOG_OBJECT (evaspixmapsink, + "Encoding %d, name %s, max wxh %lux%lu rate %d/%d", + i, encodings[i].name, encodings[i].width, encodings[i].height, + encodings[i].rate.numerator, encodings[i].rate.denominator); + if (strcmp (encodings[i].name, "XV_IMAGE") == 0) { + max_w = encodings[i].width; + max_h = encodings[i].height; +#ifdef GST_EXT_XV_ENHANCEMENT + evaspixmapsink->scr_w = max_w; + evaspixmapsink->scr_h = max_h; +#endif + } + } + + XvFreeEncodingInfo (encodings); + + /* We get all image formats supported by our port */ + formats = XvListImageFormats (xcontext->disp, + xcontext->xv_port_id, &nb_formats); + caps = gst_caps_new_empty (); + for (i = 0; i < nb_formats; i++) { + GstCaps *format_caps = NULL; + gboolean is_rgb_format = FALSE; + GstVideoFormat vformat; + + /* We set the image format of the xcontext to an existing one. This + is just some valid image format for making our xshm calls check before + caps negotiation really happens. */ + xcontext->im_format = formats[i].id; + + switch (formats[i].type) { + case XvRGB: + { + XvImageFormatValues *fmt = &(formats[i]); + gint endianness = G_BIG_ENDIAN; + + if (fmt->byte_order == LSBFirst) { + /* our caps system handles 24/32bpp RGB as big-endian. */ + if (fmt->bits_per_pixel == 24 || fmt->bits_per_pixel == 32) { + fmt->red_mask = GUINT32_TO_BE (fmt->red_mask); + fmt->green_mask = GUINT32_TO_BE (fmt->green_mask); + fmt->blue_mask = GUINT32_TO_BE (fmt->blue_mask); + + if (fmt->bits_per_pixel == 24) { + fmt->red_mask >>= 8; + fmt->green_mask >>= 8; + fmt->blue_mask >>= 8; + } + } else + endianness = G_LITTLE_ENDIAN; + } + + format_caps = gst_caps_new_simple ("video/x-raw", + "endianness", G_TYPE_INT, endianness, + "depth", G_TYPE_INT, fmt->depth, + "bpp", G_TYPE_INT, fmt->bits_per_pixel, + "red_mask", G_TYPE_INT, fmt->red_mask, + "green_mask", G_TYPE_INT, fmt->green_mask, + "blue_mask", G_TYPE_INT, fmt->blue_mask, + "width", GST_TYPE_INT_RANGE, 1, max_w, + "height", GST_TYPE_INT_RANGE, 1, max_h, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); + + is_rgb_format = TRUE; + break; + } + case XvYUV: + vformat = gst_video_format_from_fourcc (formats[i].id); + if (vformat == GST_VIDEO_FORMAT_UNKNOWN) + break; + format_caps = gst_caps_new_simple ("video/x-raw", + "format", G_TYPE_STRING, gst_video_format_to_string (vformat), + "width", GST_TYPE_INT_RANGE, 1, max_w, + "height", GST_TYPE_INT_RANGE, 1, max_h, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); + break; + default: + g_assert_not_reached (); + break; + } + + if (format_caps) { + GstEvasPixmapFormat *format = NULL; + + format = g_new0 (GstEvasPixmapFormat, 1); + if (format) { + format->format = formats[i].id; + format->caps = gst_caps_copy (format_caps); + xcontext->formats_list = g_list_append (xcontext->formats_list, format); + } + + if (is_rgb_format) { + if (rgb_caps == NULL) + rgb_caps = format_caps; + else + gst_caps_append (rgb_caps, format_caps); + } else + gst_caps_append (caps, format_caps); + } + } + + /* Collected all caps into either the caps or rgb_caps structures. + * Append rgb_caps on the end of YUV, so that YUV is always preferred */ + if (rgb_caps) + gst_caps_append (caps, rgb_caps); + + if (formats) + XFree (formats); + + GST_DEBUG_OBJECT (evaspixmapsink,"Generated the following caps: %" GST_PTR_FORMAT, caps); + + if (gst_caps_is_empty (caps)) { + gst_caps_unref (caps); + XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0); + GST_ELEMENT_ERROR (evaspixmapsink, STREAM, WRONG_TYPE, (NULL), + ("No supported format found")); + return NULL; + } + + return caps; +} + +static gpointer +gst_evaspixmapsink_event_thread (GstEvasPixmapSink * evaspixmapsink) +{ + g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), NULL); + int damage_base = 0; + int damage_err_base = 0; + int damage_case = 0; + XEvent e; + + GST_OBJECT_LOCK (evaspixmapsink); + + if (!XDamageQueryExtension(evaspixmapsink->xcontext->disp, &damage_base, &damage_err_base)) { + GST_ERROR_OBJECT (evaspixmapsink,"XDamageQueryExtension() failed"); + return NULL; + } + damage_case = (int)damage_base + XDamageNotify; + + while (evaspixmapsink->running) { + GST_OBJECT_UNLOCK (evaspixmapsink); + if (evaspixmapsink->xpixmap) { + g_mutex_lock (evaspixmapsink->x_lock); + while (XPending (evaspixmapsink->xcontext->disp)) { + XNextEvent (evaspixmapsink->xcontext->disp, &e); + if (e.type == damage_case ) { + XDamageNotifyEvent *damage_ev = (XDamageNotifyEvent *)&e; + if (damage_ev->drawable == evaspixmapsink->xpixmap->pixmap) { + ecore_pipe_write(evaspixmapsink->epipe, evaspixmapsink, sizeof(GstEvasPixmapSink)); + GST_DEBUG_OBJECT (evaspixmapsink,"event_handler : after call ecore_pipe_write()"); + } + XDamageSubtract (evaspixmapsink->xcontext->disp, evaspixmapsink->damage, None, None ); + } + } + g_mutex_unlock (evaspixmapsink->x_lock); + } else { + GST_DEBUG_OBJECT (evaspixmapsink,"event_handler : what(%d)? skip..", e.type); + break; + } + g_usleep (G_USEC_PER_SEC / 40); + GST_OBJECT_LOCK (evaspixmapsink); + } + GST_OBJECT_UNLOCK (evaspixmapsink); + return NULL; +} + +static void +gst_evaspixmapsink_manage_event_thread (GstEvasPixmapSink *evaspixmapsink) +{ + GThread *thread = NULL; + + /* don't start the thread too early */ + if (evaspixmapsink->xcontext == NULL) { + GST_ERROR_OBJECT (evaspixmapsink,"xcontext is NULL.."); + return; + } + + GST_OBJECT_LOCK (evaspixmapsink); + + if (!evaspixmapsink->event_thread) { + /* Setup our event listening thread */ + GST_DEBUG_OBJECT (evaspixmapsink,"run xevent thread"); + evaspixmapsink->running = TRUE; + evaspixmapsink->event_thread = g_thread_create ( (GThreadFunc) gst_evaspixmapsink_event_thread, evaspixmapsink, TRUE, NULL); + } else { + GST_WARNING_OBJECT (evaspixmapsink,"there already existed the event_thread.. keep going"); + /* Do not finalize the thread in here, Only finalize the thread by calling gst_evaspixmapsink_reset() */ + } + + GST_OBJECT_UNLOCK (evaspixmapsink); +} + + +/* This function calculates the pixel aspect ratio based on the properties + * in the xcontext structure and stores it there. */ +static void +gst_evaspixmapsink_calculate_pixel_aspect_ratio (GstXContext *xcontext) +{ + static const 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 */ + {64, 45}, /* 1280x1024 on 16:9 display */ + {5, 3}, /* 1280x1024 on 4:3 display */ + {4, 3} /* 800x600 on 16:9 display */ + }; + 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]); + + g_free (xcontext->par); + xcontext->par = g_new0 (GValue, 1); + g_value_init (xcontext->par, GST_TYPE_FRACTION); + gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]); + GST_DEBUG ("set xcontext PAR to %d/%d", + gst_value_get_fraction_numerator (xcontext->par), + gst_value_get_fraction_denominator (xcontext->par)); +} + +/* 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 */ +static GstXContext* +gst_evaspixmapsink_xcontext_get (GstEvasPixmapSink *evaspixmapsink) +{ + GstXContext *xcontext = NULL; + XPixmapFormatValues *px_formats = NULL; + gint nb_formats = 0, i, j, N_attr; + XvAttribute *xv_attr; + Atom prop_atom; + const char *channels[4] = { "XV_HUE", "XV_SATURATION", "XV_BRIGHTNESS", "XV_CONTRAST"}; + + g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), NULL); + + xcontext = g_new0 (GstXContext, 1); + xcontext->im_format = 0; + + g_mutex_lock (evaspixmapsink->x_lock); + + xcontext->disp = XOpenDisplay (evaspixmapsink->display_name); + + if (!xcontext->disp) { + g_mutex_unlock (evaspixmapsink->x_lock); + g_free (xcontext); + GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE, ("Could not initialise Xv output"), ("Could not open display")); + return NULL; + } + + xcontext->screen = DefaultScreenOfDisplay (xcontext->disp); + xcontext->screen_num = DefaultScreen (xcontext->disp); + xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num); + xcontext->root = DefaultRootWindow (xcontext->disp); + xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num); + xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num); + xcontext->depth = DefaultDepthOfScreen (xcontext->screen); + + xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num); + xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num); + xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num); + xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num); + + GST_DEBUG_OBJECT (evaspixmapsink,"X reports %dx%d pixels and %d mm x %d mm", xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm); + + gst_evaspixmapsink_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_mutex_unlock (evaspixmapsink->x_lock); + g_free (xcontext->par); + g_free (xcontext); + GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, SETTINGS, + ("Could not initialise Xv output"), ("Could not get pixel formats")); + 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; + + /* 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->visual->red_mask = GUINT32_TO_BE (xcontext->visual->red_mask); + xcontext->visual->green_mask = GUINT32_TO_BE (xcontext->visual->green_mask); + xcontext->visual->blue_mask = GUINT32_TO_BE (xcontext->visual->blue_mask); + if (xcontext->bpp == 24) { + xcontext->visual->red_mask >>= 8; + xcontext->visual->green_mask >>= 8; + xcontext->visual->blue_mask >>= 8; + } + } + + xcontext->caps = gst_evaspixmapsink_get_xv_support (evaspixmapsink, xcontext); + + if (!xcontext->caps) { + XCloseDisplay (xcontext->disp); + g_mutex_unlock (evaspixmapsink->x_lock); + g_free (xcontext->par); + g_free (xcontext); + /* GST_ELEMENT_ERROR is thrown by gst_evaspixmapsink_get_xv_support */ + return NULL; + } + #ifdef HAVE_XSHM + /* Search for XShm extension support */ + if (XShmQueryExtension (xcontext->disp) && gst_evaspixmapsink_check_xshm_calls (xcontext)) { + xcontext->use_xshm = TRUE; + GST_DEBUG_OBJECT (evaspixmapsink,"evaspixmapsink is using XShm extension"); + } else + #endif /* HAVE_XSHM */ + { + xcontext->use_xshm = FALSE; + GST_DEBUG_OBJECT (evaspixmapsink,"evaspixmapsink is not using XShm extension"); + } + + xv_attr = XvQueryPortAttributes (xcontext->disp, xcontext->xv_port_id, &N_attr); + + /* Generate the channels list */ + for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) { + XvAttribute *matching_attr = NULL; + + /* Retrieve the property atom if it exists. If it doesn't exist, + * the attribute itself must not either, so we can skip */ + prop_atom = XInternAtom (xcontext->disp, channels[i], True); + if (prop_atom == None) { + continue; + } + + if (xv_attr != NULL) { + for (j = 0; j < N_attr && matching_attr == NULL; ++j) { + if (!g_ascii_strcasecmp (channels[i], xv_attr[j].name)) { + matching_attr = xv_attr + j; + } + } + } + + if (matching_attr) { + GstColorBalanceChannel *channel; + channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL); + channel->label = g_strdup (channels[i]); + channel->min_value = matching_attr->min_value; + channel->max_value = matching_attr->max_value; + + xcontext->channels_list = g_list_append (xcontext->channels_list, channel); + + /* If the colorbalance settings have not been touched we get Xv values + as defaults and update our internal variables */ + if (!evaspixmapsink->cb_changed) { + gint val; + XvGetPortAttribute (xcontext->disp, xcontext->xv_port_id, prop_atom, &val); + /* Normalize val to [-1000, 1000] */ + val = floor (0.5 + -1000 + 2000 * (val - channel->min_value) / (double) (channel->max_value - channel->min_value)); + + if (!g_ascii_strcasecmp (channels[i], "XV_HUE")) { + evaspixmapsink->hue = val; + } else if (!g_ascii_strcasecmp (channels[i], "XV_SATURATION")) { + evaspixmapsink->saturation = val; + } else if (!g_ascii_strcasecmp (channels[i], "XV_BRIGHTNESS")) { + evaspixmapsink->brightness = val; + } else if (!g_ascii_strcasecmp (channels[i], "XV_CONTRAST")) { + evaspixmapsink->contrast = val; + } + } + } + } + + if (xv_attr) { + XFree (xv_attr); + } + + g_mutex_unlock (evaspixmapsink->x_lock); + + return xcontext; +} + +/* This function cleans the X context. Closing the Display, releasing the XV + port and unrefing the caps for supported formats. */ +static void +gst_evaspixmapsink_xcontext_clear (GstEvasPixmapSink *evaspixmapsink) +{ + GList *formats_list, *channels_list; + GstXContext *xcontext; + gint i = 0; + + g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink)); + + GST_OBJECT_LOCK (evaspixmapsink); + if (evaspixmapsink->xcontext == NULL) { + GST_OBJECT_UNLOCK (evaspixmapsink); + return; + } + + /* Take the XContext from the sink and clean it up */ + xcontext = evaspixmapsink->xcontext; + evaspixmapsink->xcontext = NULL; + + GST_OBJECT_UNLOCK (evaspixmapsink); + + formats_list = xcontext->formats_list; + + while (formats_list) { + GstEvasPixmapFormat *format = formats_list->data; + + gst_caps_unref (format->caps); + g_free (format); + formats_list = g_list_next (formats_list); + } + + if (xcontext->formats_list) + g_list_free (xcontext->formats_list); + + channels_list = xcontext->channels_list; + + while (channels_list) { + GstColorBalanceChannel *channel = channels_list->data; + + g_object_unref (channel); + channels_list = g_list_next (channels_list); + } + + if (xcontext->channels_list) + g_list_free (xcontext->channels_list); + + gst_caps_unref (xcontext->caps); + + for (i = 0; i < xcontext->nb_adaptors; i++) { + g_free (xcontext->adaptors[i]); + } + + g_free (xcontext->adaptors); + + g_free (xcontext->par); + + g_mutex_lock (evaspixmapsink->x_lock); + + GST_DEBUG_OBJECT (evaspixmapsink,"Closing display and freeing X Context"); + + XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0); + + XCloseDisplay (xcontext->disp); + + g_mutex_unlock (evaspixmapsink->x_lock); + + g_free (xcontext); +} + +/* Element stuff */ + +/* This function tries to get a format matching with a given caps in the + supported list of formats we generated in gst_evaspixmapsink_get_xv_support */ +static gint +gst_evaspixmapsink_get_format_from_caps (GstEvasPixmapSink *evaspixmapsink, GstCaps *caps) +{ + GList *list = NULL; + + g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), 0); + + list = evaspixmapsink->xcontext->formats_list; + + while (list) { + GstEvasPixmapFormat *format = list->data; + + if (format) { + if (gst_caps_can_intersect (caps, format->caps)) { + return format->format; + } + } + list = g_list_next (list); + } + + return -1; +} + +static GstCaps * +gst_evaspixmapsink_getcaps (GstBaseSink *bsink, GstCaps *filter) +{ + GstEvasPixmapSink *evaspixmapsink; + GstCaps* pad_caps; + + evaspixmapsink = GST_EVASPIXMAPSINK (bsink); + + if(filter) + GST_LOG_OBJECT (evaspixmapsink,"filter caps %" GST_PTR_FORMAT, filter); + if(evaspixmapsink->xcontext) + GST_LOG_OBJECT (evaspixmapsink,"context caps %" GST_PTR_FORMAT, evaspixmapsink->xcontext->caps); + + if (evaspixmapsink->xcontext) + return filter ? gst_caps_intersect(filter, evaspixmapsink->xcontext->caps) + : gst_caps_ref (evaspixmapsink->xcontext->caps); + + pad_caps = gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD(evaspixmapsink)); + return + filter ? gst_caps_intersect(filter, pad_caps) : gst_caps_copy (pad_caps); +} + +static gboolean +gst_evaspixmapsink_setcaps (GstBaseSink *bsink, GstCaps *caps) +{ + GstEvasPixmapSink *evaspixmapsink; + GstStructure *structure; + guint32 im_format = 0; + gboolean ret; + gint video_width, video_height; + gint disp_x, disp_y; + gint disp_width, disp_height; + gint video_par_n, video_par_d; /* video's PAR */ + gint display_par_n, display_par_d; /* display's PAR */ + const GValue *caps_par; + const GValue *caps_disp_reg; + const GValue *fps; + guint num, den; +#ifdef GST_EXT_XV_ENHANCEMENT + gboolean enable_last_buffer; +#endif + + evaspixmapsink = GST_EVASPIXMAPSINK (bsink); + + GST_DEBUG_OBJECT (evaspixmapsink,"In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %" GST_PTR_FORMAT, evaspixmapsink->xcontext->caps, caps); + + if (!gst_caps_can_intersect (evaspixmapsink->xcontext->caps, caps)) { + goto incompatible_caps; + } + + evaspixmapsink->negotiated_caps = gst_caps_copy(caps); + structure = gst_caps_get_structure (caps, 0); + ret = gst_structure_get_int (structure, "width", &video_width); + ret &= gst_structure_get_int (structure, "height", &video_height); + fps = gst_structure_get_value (structure, "framerate"); + ret &= (fps != NULL); + + if (!ret) { + goto incomplete_caps; + } + +#ifdef GST_EXT_XV_ENHANCEMENT + evaspixmapsink->aligned_width = video_width; + evaspixmapsink->aligned_height = video_height; + + /* get enable-last-buffer */ + g_object_get(G_OBJECT(evaspixmapsink), "enable-last-buffer", &enable_last_buffer, NULL); + GST_INFO_OBJECT (evaspixmapsink,"current enable-last-buffer : %d", enable_last_buffer); + /* flush if enable-last-buffer is TRUE */ + if (enable_last_buffer) { + GST_INFO_OBJECT (evaspixmapsink,"flush last-buffer"); + g_object_set(G_OBJECT(evaspixmapsink), "enable-last-buffer", FALSE, NULL); + g_object_set(G_OBJECT(evaspixmapsink), "enable-last-buffer", TRUE, NULL); + } +#endif + + evaspixmapsink->fps_n = gst_value_get_fraction_numerator (fps); + evaspixmapsink->fps_d = gst_value_get_fraction_denominator (fps); + + evaspixmapsink->video_width = video_width; + evaspixmapsink->video_height = video_height; + + im_format = gst_evaspixmapsink_get_format_from_caps (evaspixmapsink, caps); + if (im_format == -1) { + goto invalid_format; + } + + /* get aspect ratio from caps if it's present, and + * convert video width and height to a display width and height + * using wd / hd = wv / hv * PARv / PARd */ + + /* get video's PAR */ + caps_par = gst_structure_get_value (structure, "pixel-aspect-ratio"); + if (caps_par) { + video_par_n = gst_value_get_fraction_numerator (caps_par); + video_par_d = gst_value_get_fraction_denominator (caps_par); + } else { + video_par_n = 1; + video_par_d = 1; + } + /* get display's PAR */ + if (evaspixmapsink->par) { + display_par_n = gst_value_get_fraction_numerator (evaspixmapsink->par); + display_par_d = gst_value_get_fraction_denominator (evaspixmapsink->par); + } else { + display_par_n = 1; + display_par_d = 1; + } + + /* get the display region */ + caps_disp_reg = gst_structure_get_value (structure, "display-region"); + if (caps_disp_reg) { + disp_x = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 0)); + disp_y = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 1)); + disp_width = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 2)); + disp_height = g_value_get_int (gst_value_array_get_value (caps_disp_reg, 3)); + } else { + disp_x = disp_y = 0; + disp_width = video_width; + disp_height = video_height; + } + + if (!gst_video_calculate_display_ratio (&num, &den, video_width, video_height, video_par_n, video_par_d, display_par_n, display_par_d)) { + goto no_disp_ratio; + } + + evaspixmapsink->disp_x = disp_x; + evaspixmapsink->disp_y = disp_y; + evaspixmapsink->disp_width = disp_width; + evaspixmapsink->disp_height = disp_height; + + GST_DEBUG_OBJECT (evaspixmapsink,"video width/height: %dx%d, calculated display ratio: %d/%d", video_width, video_height, num, den); + + /* now find a width x height that respects this display ratio. + * prefer those that have one of w/h the same as the incoming video + * using wd / hd = num / den */ + + /* start with same height, because of interlaced video */ + /* check hd / den is an integer scale factor, and scale wd with the PAR */ + if (video_height % den == 0) { + GST_DEBUG_OBJECT (evaspixmapsink,"keeping video height"); + GST_VIDEO_SINK_WIDTH (evaspixmapsink) = (guint) gst_util_uint64_scale_int (video_height, num, den); + GST_VIDEO_SINK_HEIGHT (evaspixmapsink) = video_height; + } else if (video_width % num == 0) { + GST_DEBUG_OBJECT (evaspixmapsink,"keeping video width"); + GST_VIDEO_SINK_WIDTH (evaspixmapsink) = video_width; + GST_VIDEO_SINK_HEIGHT (evaspixmapsink) = (guint) gst_util_uint64_scale_int (video_width, den, num); + } else { + GST_DEBUG_OBJECT (evaspixmapsink,"approximating while keeping video height"); + GST_VIDEO_SINK_WIDTH (evaspixmapsink) = (guint) gst_util_uint64_scale_int (video_height, num, den); + GST_VIDEO_SINK_HEIGHT (evaspixmapsink) = video_height; + } + GST_DEBUG_OBJECT (evaspixmapsink,"scaling to %dx%d", GST_VIDEO_SINK_WIDTH (evaspixmapsink), GST_VIDEO_SINK_HEIGHT (evaspixmapsink)); + + /* Creating our window and our image with the display size in pixels */ + if (GST_VIDEO_SINK_WIDTH (evaspixmapsink) <= 0 || GST_VIDEO_SINK_HEIGHT (evaspixmapsink) <= 0) { + goto no_display_size; + } + + g_mutex_lock (evaspixmapsink->flow_lock); + + /* We renew our evaspixmap buffer only if size or format changed; + * the evaspixmap buffer is the same size as the video pixel size */ + if ((evaspixmapsink->evas_pixmap_buf) && ((im_format != evaspixmapsink->evas_pixmap_buf->im_format) + || (video_width != evaspixmapsink->evas_pixmap_buf->width) || (video_height != evaspixmapsink->evas_pixmap_buf->height))) { + GST_DEBUG_OBJECT (evaspixmapsink,"old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (evaspixmapsink->evas_pixmap_buf->im_format), GST_FOURCC_ARGS (im_format)); + GST_DEBUG_OBJECT (evaspixmapsink,"renewing evaspixmap buffer"); + g_boxed_free(GST_TYPE_EVASPIXMAP_BUFFER, evaspixmapsink->evas_pixmap_buf); + evaspixmapsink->evas_pixmap_buf = NULL; + } + + g_mutex_unlock (evaspixmapsink->flow_lock); + + if (evaspixmapsink->eo) { + if (!gst_evaspixmapsink_xpixmap_link (evaspixmapsink)) { + GST_ERROR_OBJECT (evaspixmapsink,"link evas image object with pixmap failed..."); + return FALSE; + } else { + gst_evaspixmapsink_manage_event_thread (evaspixmapsink); + } + } else { + GST_ERROR_OBJECT (evaspixmapsink,"setcaps success, but there is no evas image object.."); + return FALSE; + } + + return TRUE; + + /* ERRORS */ + incompatible_caps: + { + GST_ERROR_OBJECT (evaspixmapsink,"caps incompatible"); + return FALSE; + } + incomplete_caps: + { + GST_DEBUG_OBJECT (evaspixmapsink,"Failed to retrieve either width, ""height or framerate from intersected caps"); + return FALSE; + } + invalid_format: + { + GST_DEBUG_OBJECT (evaspixmapsink,"Could not locate image format from caps %" GST_PTR_FORMAT, caps); + return FALSE; + } + no_disp_ratio: + { + GST_ELEMENT_ERROR (evaspixmapsink, CORE, NEGOTIATION, (NULL), ("Error calculating the output display ratio of the video.")); + return FALSE; + } + no_display_size: + { + GST_ELEMENT_ERROR (evaspixmapsink, CORE, NEGOTIATION, (NULL), ("Error calculating the output display ratio of the video.")); + return FALSE; + } +} + +static GstStateChangeReturn +gst_evaspixmapsink_change_state (GstElement *element, GstStateChange transition) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + GstEvasPixmapSink *evaspixmapsink; + + evaspixmapsink = GST_EVASPIXMAPSINK (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_NULL_TO_READY"); + + /* open drm to use gem */ + if (drm_init(evaspixmapsink)) { + GST_ERROR_OBJECT (evaspixmapsink,"drm_init() failure"); + return GST_STATE_CHANGE_FAILURE; + } + + /* check if there exist evas image object, need to write code related to making internal evas image object */ + if (!is_evas_image_object (evaspixmapsink->eo)) { + GST_ERROR_OBJECT (evaspixmapsink,"There is no evas image object.."); + return GST_STATE_CHANGE_FAILURE; + } + + /* Set xcontext and display */ + if (!evaspixmapsink->xcontext) { + evaspixmapsink->xcontext = gst_evaspixmapsink_xcontext_get (evaspixmapsink); + if (!evaspixmapsink->xcontext) { + GST_ERROR_OBJECT (evaspixmapsink,"could not get xcontext.."); + return GST_STATE_CHANGE_FAILURE; + } + } + + /* update object's par with calculated one if not set yet */ + if (!evaspixmapsink->par) { + evaspixmapsink->par = g_new0 (GValue, 1); + gst_value_init_and_copy (evaspixmapsink->par, evaspixmapsink->xcontext->par); + GST_DEBUG_OBJECT (evaspixmapsink,"set calculated PAR on object's PAR"); + } + + /* call XSynchronize with the current value of synchronous */ + GST_DEBUG_OBJECT (evaspixmapsink,"XSynchronize called with %s", evaspixmapsink->synchronous ? "TRUE" : "FALSE"); + XSynchronize (evaspixmapsink->xcontext->disp, evaspixmapsink->synchronous); + gst_evaspixmapsink_update_colorbalance (evaspixmapsink); + break; + + case GST_STATE_CHANGE_READY_TO_PAUSED: + GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_READY_TO_PAUSED"); + break; + + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + GST_DEBUG_OBJECT (evaspixmapsink,"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: + GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_PLAYING_TO_PAUSED"); + break; + + case GST_STATE_CHANGE_PAUSED_TO_READY: + GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_PAUSED_TO_READY"); + evaspixmapsink->fps_n = 0; + evaspixmapsink->fps_d = 1; + GST_VIDEO_SINK_WIDTH (evaspixmapsink) = 0; + GST_VIDEO_SINK_HEIGHT (evaspixmapsink) = 0; + break; + + case GST_STATE_CHANGE_READY_TO_NULL: + GST_DEBUG_OBJECT (evaspixmapsink,"GST_STATE_CHANGE_READY_TO_NULL"); + gst_evaspixmapsink_reset (evaspixmapsink); + /* close drm */ + drm_fini(evaspixmapsink); + break; + + default: + break; + } + return ret; +} + +static void +gst_evaspixmapsink_get_times (GstBaseSink *bsink, GstBuffer *buf, GstClockTime *start, GstClockTime *end) +{ + GstEvasPixmapSink *evaspixmapsink; + + evaspixmapsink = GST_EVASPIXMAPSINK (bsink); + + if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { + *start = GST_BUFFER_TIMESTAMP (buf); + if (GST_BUFFER_DURATION_IS_VALID (buf)) { + *end = *start + GST_BUFFER_DURATION (buf); + } else { + if (evaspixmapsink->fps_n > 0) { + *end = *start + + gst_util_uint64_scale_int (GST_SECOND, evaspixmapsink->fps_d, + evaspixmapsink->fps_n); + } + } + } +} + +static GstFlowReturn +gst_evaspixmapsink_show_frame (GstVideoSink *vsink, GstBuffer *buf) +{ + GstMapInfo buf_info = GST_MAP_INFO_INIT; + GstEvasPixmapSink *evaspixmapsink; +#ifdef GST_EXT_XV_ENHANCEMENT + XV_PUTIMAGE_DATA_PTR img_data = NULL; + SCMN_IMGB *scmn_imgb = NULL; + gint format = 0; +#endif + evaspixmapsink = GST_EVASPIXMAPSINK (vsink); + +#ifdef GST_EXT_XV_ENHANCEMENT + if( evaspixmapsink->stop_video ) { + GST_INFO_OBJECT (evaspixmapsink, "Stop video is TRUE. so skip show frame..." ); + return GST_FLOW_OK; + } +#endif + + if (!evaspixmapsink->evas_pixmap_buf) { + GST_DEBUG_OBJECT (evaspixmapsink,"creating our evaspixmap buffer"); +#ifdef GST_EXT_XV_ENHANCEMENT + format = gst_evaspixmapsink_get_format_from_caps(evaspixmapsink, evaspixmapsink->negotiated_caps); + + switch (format) { + case GST_MAKE_FOURCC('S', 'T', '1', '2'): + case GST_MAKE_FOURCC('S', 'N', '1', '2'): + case GST_MAKE_FOURCC('S', '4', '2', '0'): + case GST_MAKE_FOURCC('S', 'U', 'Y', '2'): + case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'): + case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'): + gst_buffer_map(buf, &buf_info, GST_MAP_READ); + scmn_imgb = (SCMN_IMGB *)buf_info.data; + gst_buffer_unmap(buf, &buf_info); + if(scmn_imgb == NULL) { + GST_DEBUG_OBJECT (evaspixmapsink, "scmn_imgb is NULL. Skip buffer put..." ); + return GST_FLOW_OK; + } + /* skip buffer if aligned size is smaller than size of caps */ + if (scmn_imgb->s[0] < evaspixmapsink->video_width || scmn_imgb->e[0] < evaspixmapsink->video_height) { + GST_WARNING_OBJECT (evaspixmapsink,"invalid size[caps:%dx%d,aligned:%dx%d]. Skip this buffer...", + evaspixmapsink->video_width, evaspixmapsink->video_height, scmn_imgb->s[0], scmn_imgb->e[0]); + return GST_FLOW_OK; + } + evaspixmapsink->aligned_width = scmn_imgb->s[0]; + evaspixmapsink->aligned_height = scmn_imgb->e[0]; + GST_DEBUG_OBJECT (evaspixmapsink,"video width,height[%dx%d]",evaspixmapsink->video_width, evaspixmapsink->video_height); + GST_INFO_OBJECT (evaspixmapsink,"Use aligned width,height[%dx%d]",evaspixmapsink->aligned_width, evaspixmapsink->aligned_height); + break; + default: + GST_INFO_OBJECT (evaspixmapsink,"Use original width,height of caps"); + break; + } +#endif + evaspixmapsink->evas_pixmap_buf = gst_evaspixmap_buffer_new (evaspixmapsink, evaspixmapsink->negotiated_caps); + + if (!evaspixmapsink->evas_pixmap_buf) { + /* The create method should have posted an informative error */ + goto no_image; + } + if (evaspixmapsink->evas_pixmap_buf->size < gst_buffer_get_size (buf)) { + GST_ELEMENT_ERROR (evaspixmapsink, RESOURCE, WRITE, ("Failed to create output image buffer of %dx%d pixels", evaspixmapsink->evas_pixmap_buf->width, evaspixmapsink->evas_pixmap_buf->height),("XServer allocated buffer size did not match input buffer")); + gst_evaspixmap_buffer_destroy (evaspixmapsink->evas_pixmap_buf); + evaspixmapsink->evas_pixmap_buf = NULL; + goto no_image; + } + } + +#ifdef GST_EXT_XV_ENHANCEMENT + switch (evaspixmapsink->evas_pixmap_buf->im_format) { + /* Cases for specified formats of Samsung extension */ + case GST_MAKE_FOURCC('S', 'T', '1', '2'): + case GST_MAKE_FOURCC('S', 'N', '1', '2'): + case GST_MAKE_FOURCC('S', '4', '2', '0'): + case GST_MAKE_FOURCC('S', 'U', 'Y', '2'): + case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'): + case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'): + case GST_MAKE_FOURCC('I', 'T', 'L', 'V'): + { + GST_DEBUG_OBJECT (evaspixmapsink, "Samsung extension display format activated. fourcc:%c%c%c%c", + evaspixmapsink->evas_pixmap_buf->im_format, evaspixmapsink->evas_pixmap_buf->im_format>>8, + evaspixmapsink->evas_pixmap_buf->im_format>>16, evaspixmapsink->evas_pixmap_buf->im_format>>24); + GstMapInfo buf_info = GST_MAP_INFO_INIT; + + if (evaspixmapsink->evas_pixmap_buf->xvimage->data) { + img_data = (XV_PUTIMAGE_DATA_PTR) evaspixmapsink->evas_pixmap_buf->xvimage->data; + XV_PUTIMAGE_INIT_DATA(img_data); + gst_buffer_map(buf, &buf_info, GST_MAP_READ); + scmn_imgb = (SCMN_IMGB *)buf_info.data; + gst_buffer_unmap(buf, &buf_info); + if (scmn_imgb == NULL) { + GST_DEBUG_OBJECT (evaspixmapsink, "scmn_imgb is NULL. Skip buffer put..." ); + return GST_FLOW_OK; + } + + if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_PADDR) { + img_data->YBuf = (unsigned int)scmn_imgb->p[0]; + img_data->CbBuf = (unsigned int)scmn_imgb->p[1]; + img_data->CrBuf = (unsigned int)scmn_imgb->p[2]; + img_data->BufType = XV_BUF_TYPE_LEGACY; + if (!img_data->YBuf) { + GST_WARNING_OBJECT (evaspixmapsink, "img_data->YBuf is NULL. skip buffer put..." ); + return GST_FLOW_OK; + } + } else { /* BUF_SHARE_METHOD_FD */ + /* convert dma-buf fd into drm gem name */ + img_data->YBuf = drm_convert_dmabuf_gemname(evaspixmapsink, (int)scmn_imgb->dma_buf_fd[0]); + img_data->CbBuf = drm_convert_dmabuf_gemname(evaspixmapsink, (int)scmn_imgb->dma_buf_fd[1]); + img_data->CrBuf = drm_convert_dmabuf_gemname(evaspixmapsink, (int)scmn_imgb->dma_buf_fd[2]); + img_data->BufType = XV_BUF_TYPE_DMABUF; + if (!img_data->YBuf) { + GST_WARNING_OBJECT (evaspixmapsink, "img_data->YBuf is NULL. skip buffer put..." ); + return GST_FLOW_OK; + } + } + GST_LOG_OBJECT(evaspixmapsink, "YBuf[%d], CbBuf[%d], CrBuf[%d]", + img_data->YBuf, img_data->CbBuf, img_data->CrBuf ); + } else { + GST_WARNING_OBJECT (evaspixmapsink, "xvimage->data is NULL. skip buffer put..." ); + return GST_FLOW_OK; + } + break; + } + default: + { + GST_DEBUG_OBJECT (evaspixmapsink, "Normal format activated. fourcc:%c%c%c%c", + evaspixmapsink->evas_pixmap_buf->im_format, evaspixmapsink->evas_pixmap_buf->im_format>>8, + evaspixmapsink->evas_pixmap_buf->im_format>>16, evaspixmapsink->evas_pixmap_buf->im_format>>24); + gst_buffer_map(buf, &buf_info, GST_MAP_READ); + memcpy (evaspixmapsink->evas_pixmap_buf->xvimage->data, buf_info.data, + MIN (buf_info.size, evaspixmapsink->evas_pixmap_buf->size)); + gst_buffer_unmap(buf, &buf_info); + break; + } + } +#else + gst_buffer_map(buf, &buf_info, GST_MAP_READ); + memcpy (evaspixmapsink->evas_pixmap_buf->xvimage->data, buf_info.data, MIN (buf_info.size, evaspixmapsink->evas_pixmap_buf->size)); + gst_buffer_unmap(buf, &buf_info); +#endif + if (!gst_evaspixmap_buffer_put (evaspixmapsink, evaspixmapsink->evas_pixmap_buf)) { + goto no_pixmap; + } + + return GST_FLOW_OK; + + /* ERRORS */ + no_image: + { + /* No image available. That's very bad ! */ + GST_WARNING_OBJECT (evaspixmapsink,"could not create image"); + return GST_FLOW_ERROR; + } + no_pixmap: + { + /* No Pixmap available to put our image into */ + GST_WARNING_OBJECT (evaspixmapsink,"could not output image - no pixmap"); + return GST_FLOW_ERROR; + } +} + +static gboolean +gst_evaspixmapsink_event (GstBaseSink *sink, GstEvent *event) +{ + GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (sink); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_START: + GST_DEBUG_OBJECT (evaspixmapsink,"GST_EVENT_FLUSH_START"); + break; + case GST_EVENT_FLUSH_STOP: + GST_DEBUG_OBJECT (evaspixmapsink,"GST_EVENT_FLUSH_STOP"); + break; + default: + break; + } + if (GST_BASE_SINK_CLASS (parent_class)->event) { + return GST_BASE_SINK_CLASS (parent_class)->event (sink, event); + } else { + return TRUE; + } +} + +/* Interfaces stuff */ + +static void +gst_evaspixmapsink_navigation_send_event (GstNavigation *navigation, GstStructure *structure) +{ + GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (navigation); + GstPad *peer; + + if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (evaspixmapsink)))) { + GstEvent *event; + GstVideoRectangle src, dst, result; + gdouble x, y, xscale = 1.0, yscale = 1.0; + + event = gst_event_new_navigation (structure); + + /* We take the flow_lock while we look at the window */ + g_mutex_lock (evaspixmapsink->flow_lock); + + if (!evaspixmapsink->xpixmap) { + g_mutex_unlock (evaspixmapsink->flow_lock); + return; + } + + if (evaspixmapsink->keep_aspect) { + /* We get the frame position using the calculated geometry from _setcaps + that respect pixel aspect ratios */ + src.w = GST_VIDEO_SINK_WIDTH (evaspixmapsink); + src.h = GST_VIDEO_SINK_HEIGHT (evaspixmapsink); + dst.w = evaspixmapsink->render_rect.w; + dst.h = evaspixmapsink->render_rect.h; + + gst_video_sink_center_rect (src, dst, &result, TRUE); + result.x += evaspixmapsink->render_rect.x; + result.y += evaspixmapsink->render_rect.y; + } else { + memcpy (&result, &evaspixmapsink->render_rect, sizeof (GstVideoRectangle)); + } + + g_mutex_unlock (evaspixmapsink->flow_lock); + + /* We calculate scaling using the original video frames geometry to include + pixel aspect ratio scaling. */ + xscale = (gdouble) evaspixmapsink->video_width / result.w; + yscale = (gdouble) evaspixmapsink->video_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_evaspixmapsink_navigation_init (GstNavigationInterface *iface) +{ + iface->send_event = gst_evaspixmapsink_navigation_send_event; +} + +static const GList* +gst_evaspixmapsink_colorbalance_list_channels (GstColorBalance *balance) +{ + GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (balance); + + g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), NULL); + + if (evaspixmapsink->xcontext) + return evaspixmapsink->xcontext->channels_list; + else + return NULL; +} + +static void +gst_evaspixmapsink_colorbalance_set_value (GstColorBalance *balance, GstColorBalanceChannel *channel, gint value) +{ + GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (balance); + + g_return_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink)); + g_return_if_fail (channel->label != NULL); + + evaspixmapsink->cb_changed = TRUE; + + /* Normalize val to [-1000, 1000] */ + value = floor (0.5 + -1000 + 2000 * (value - channel->min_value) / + (double) (channel->max_value - channel->min_value)); + + if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) { + evaspixmapsink->hue = value; + } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) { + evaspixmapsink->saturation = value; + } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) { + evaspixmapsink->contrast = value; + } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) { + evaspixmapsink->brightness = value; + } else { + g_warning ("got an unknown channel %s", channel->label); + return; + } + + gst_evaspixmapsink_update_colorbalance (evaspixmapsink); +} + +static gint +gst_evaspixmapsink_colorbalance_get_value (GstColorBalance *balance, GstColorBalanceChannel *channel) +{ + GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (balance); + gint value = 0; + + g_return_val_if_fail (GST_IS_EVASPIXMAPSINK (evaspixmapsink), 0); + g_return_val_if_fail (channel->label != NULL, 0); + + if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) { + value = evaspixmapsink->hue; + } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) { + value = evaspixmapsink->saturation; + } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) { + value = evaspixmapsink->contrast; + } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) { + value = evaspixmapsink->brightness; + } else { + g_warning ("got an unknown channel %s", channel->label); + } + + /* Normalize val to [channel->min_value, channel->max_value] */ + value = channel->min_value + (channel->max_value - channel->min_value) * (value + 1000) / 2000; + + return value; +} + +static void +gst_evaspixmapsink_colorbalance_init (GstColorBalanceInterface *iface) +{ + iface->list_channels = gst_evaspixmapsink_colorbalance_list_channels; + iface->set_value = gst_evaspixmapsink_colorbalance_set_value; + iface->get_value = gst_evaspixmapsink_colorbalance_get_value; +} + +static const GList * +gst_evaspixmapsink_probe_get_properties (GstPropertyProbe *probe) +{ + GObjectClass *klass = G_OBJECT_GET_CLASS (probe); + static GList *list = NULL; + + if (!list) { + list = g_list_append (NULL, g_object_class_find_property (klass, "device")); + list = g_list_append (list, g_object_class_find_property (klass, "autopaint-colorkey")); + list = g_list_append (list, g_object_class_find_property (klass, "double-buffer")); + list = g_list_append (list, g_object_class_find_property (klass, "colorkey")); + } + + return list; +} + +static void +gst_evaspixmapsink_probe_probe_property (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec) +{ + GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (probe); + + switch (prop_id) { + case PROP_DEVICE: + case PROP_AUTOPAINT_COLORKEY: + case PROP_DOUBLE_BUFFER: + case PROP_COLORKEY: + GST_DEBUG_OBJECT (evaspixmapsink,"probing device list and get capabilities"); + if (!evaspixmapsink->xcontext) { + GST_DEBUG_OBJECT (evaspixmapsink,"generating xcontext"); + evaspixmapsink->xcontext = gst_evaspixmapsink_xcontext_get (evaspixmapsink); + if (!evaspixmapsink->xcontext) { + GST_ERROR_OBJECT (evaspixmapsink,"could not get xcontext.."); + } + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } +} + +static gboolean +gst_evaspixmapsink_probe_needs_probe (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec) +{ + GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (probe); + gboolean ret = FALSE; + + switch (prop_id) { + case PROP_DEVICE: + case PROP_AUTOPAINT_COLORKEY: + case PROP_DOUBLE_BUFFER: + case PROP_COLORKEY: + if (evaspixmapsink->xcontext != NULL) { + ret = FALSE; + } else { + ret = TRUE; + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } + + return ret; +} + +static GValueArray * +gst_evaspixmapsink_probe_get_values (GstPropertyProbe *probe, guint prop_id, const GParamSpec *pspec) +{ + GstEvasPixmapSink *evaspixmapsink = GST_EVASPIXMAPSINK (probe); + GValueArray *array = NULL; + + if (G_UNLIKELY (!evaspixmapsink->xcontext)) { + GST_WARNING_OBJECT (evaspixmapsink,"we don't have any xcontext, can't " + "get values"); + goto beach; + } + + switch (prop_id) { + case PROP_DEVICE: + { + guint i; + GValue value = { 0 }; + + array = g_value_array_new (evaspixmapsink->xcontext->nb_adaptors); + g_value_init (&value, G_TYPE_STRING); + + for (i = 0; i < evaspixmapsink->xcontext->nb_adaptors; i++) { + gchar *adaptor_id_s = g_strdup_printf ("%u", i); + + g_value_set_string (&value, adaptor_id_s); + g_value_array_append (array, &value); + g_free (adaptor_id_s); + } + g_value_unset (&value); + break; + } + case PROP_AUTOPAINT_COLORKEY: + if (evaspixmapsink->have_autopaint_colorkey) { + GValue value = { 0 }; + + array = g_value_array_new (2); + g_value_init (&value, G_TYPE_BOOLEAN); + g_value_set_boolean (&value, FALSE); + g_value_array_append (array, &value); + g_value_set_boolean (&value, TRUE); + g_value_array_append (array, &value); + g_value_unset (&value); + } + break; + case PROP_DOUBLE_BUFFER: + if (evaspixmapsink->have_double_buffer) { + GValue value = { 0 }; + + array = g_value_array_new (2); + g_value_init (&value, G_TYPE_BOOLEAN); + g_value_set_boolean (&value, FALSE); + g_value_array_append (array, &value); + g_value_set_boolean (&value, TRUE); + g_value_array_append (array, &value); + g_value_unset (&value); + } + break; + case PROP_COLORKEY: + if (evaspixmapsink->have_colorkey) { + GValue value = { 0 }; + + array = g_value_array_new (1); + g_value_init (&value, GST_TYPE_INT_RANGE); + gst_value_set_int_range (&value, 0, 0xffffff); + g_value_array_append (array, &value); + g_value_unset (&value); + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } + +beach: + return array; +} + +static void +gst_evaspixmapsink_property_probe_interface_init (GstPropertyProbeInterface *iface) +{ + iface->get_properties = gst_evaspixmapsink_probe_get_properties; + iface->probe_property = gst_evaspixmapsink_probe_probe_property; + iface->needs_probe = gst_evaspixmapsink_probe_needs_probe; + iface->get_values = gst_evaspixmapsink_probe_get_values; +} + +static gboolean +gst_evaspixmapsink_xpixmap_link (GstEvasPixmapSink *evaspixmapsink) +{ + Display *dpy; + Pixmap *pixmap_id; + int evas_object_width = 0; + int evas_object_height = 0; + int pixmap_width = 0; + int pixmap_height = 0; + int xw = 0; + int xh = 0; + + if (!evaspixmapsink) { + GST_ERROR_OBJECT (evaspixmapsink,"could not get evaspixmapsink.."); + return FALSE; + } + g_mutex_lock (evaspixmapsink->flow_lock); + + /* Set xcontext and display */ + if (!evaspixmapsink->xcontext) { + GST_WARNING_OBJECT (evaspixmapsink,"there's no xcontext, try to get one.."); + evaspixmapsink->xcontext = gst_evaspixmapsink_xcontext_get (evaspixmapsink); + if (!evaspixmapsink->xcontext) { + GST_ERROR_OBJECT (evaspixmapsink,"could not get xcontext.."); + return FALSE; + } + } + + dpy = evaspixmapsink->xcontext->disp; + + /* Set evas image object size */ + evas_object_geometry_get(evaspixmapsink->eo, NULL, NULL, &evas_object_width, &evas_object_height); + if (evaspixmapsink->use_origin_size || !evas_object_width || !evas_object_height) { + pixmap_width = evaspixmapsink->video_width; + pixmap_height = evaspixmapsink->video_height; + GST_INFO_OBJECT (evaspixmapsink,"set size to media src size(%dx%d)", pixmap_width, pixmap_height); + } + + g_mutex_lock (evaspixmapsink->x_lock); + if (evaspixmapsink->use_origin_size || !evas_object_width || !evas_object_height) { + XvQueryBestSize(dpy, evaspixmapsink->xcontext->xv_port_id,0,0,0, pixmap_width, pixmap_height, &xw, &xh); + if (!evas_object_width || !evas_object_height) { + evaspixmapsink->w = xw; + evaspixmapsink->h = xh; + } else { + evaspixmapsink->w = evas_object_width; + evaspixmapsink->h = evas_object_height; + } + GST_DEBUG_OBJECT (evaspixmapsink,"XvQueryBestSize : xv_port_id(%d), w(%d),h(%d) => xw(%d),xh(%d)", evaspixmapsink->xcontext->xv_port_id, pixmap_width, pixmap_height, xw, xh); + } else { + XvQueryBestSize(dpy, evaspixmapsink->xcontext->xv_port_id,0,0,0, evas_object_width, evas_object_height, &xw, &xh); + GST_DEBUG_OBJECT (evaspixmapsink,"XvQueryBestSize : xv_port_id(%d), w(%d),h(%d) => xw(%d),xh(%d)", evaspixmapsink->xcontext->xv_port_id, evas_object_width, evas_object_height, xw, xh); + evaspixmapsink->w = xw; + evaspixmapsink->h = xh; + } + evas_object_image_size_set(evaspixmapsink->eo, evaspixmapsink->w, evaspixmapsink->h); + + /* create xpixmap structure */ + if (!evaspixmapsink->xpixmap) { + /* xpixmap can be created in this function only */ + evaspixmapsink->xpixmap = g_new0 (GstXPixmap, 1); + if(!evaspixmapsink->xpixmap) { + GST_ERROR_OBJECT (evaspixmapsink,"xpixmap is not valid.."); + goto GO_OUT_OF_FUNC; + } + } + + /* create pixmap */ + if (!xw || !xh) { + GST_WARNING_OBJECT (evaspixmapsink,"skip creating pixmap..xw(%d),xh(%d)",xw,xh); + goto GO_OUT_OF_FUNC; + } else { + pixmap_id = XCreatePixmap(dpy, DefaultRootWindow(dpy), xw, xh, DefaultDepth(dpy, DefaultScreen(dpy))); + if ( (int)pixmap_id == BadAlloc || (int)pixmap_id == BadDrawable || (int)pixmap_id == BadValue ) { + GST_ERROR_OBJECT (evaspixmapsink,"pixmap allocation error.."); + goto GO_OUT_OF_FUNC; + } + GST_DEBUG_OBJECT (evaspixmapsink,"evas_object_width(%d),evas_object_height(%d),pixmap:%d,depth:%d", + evas_object_width,evas_object_height,pixmap_id,DefaultDepth(dpy, DefaultScreen(dpy))); + } + + if (evaspixmapsink->xpixmap->pixmap && pixmap_id != evaspixmapsink->xpixmap->pixmap) { + /* If we reset another pixmap, do below */ + GST_DEBUG_OBJECT (evaspixmapsink,"destroy former pixmap(%d)",evaspixmapsink->xpixmap->pixmap); + if (evaspixmapsink->eo) { + evas_object_image_native_surface_set(evaspixmapsink->eo, NULL); + } + g_mutex_unlock (evaspixmapsink->x_lock); + gst_evaspixmapsink_xpixmap_clear (evaspixmapsink, evaspixmapsink->xpixmap); + g_mutex_lock (evaspixmapsink->x_lock); + if(evaspixmapsink->xpixmap->pixmap) { + XFreePixmap(evaspixmapsink->xcontext->disp, evaspixmapsink->xpixmap->pixmap); + evaspixmapsink->xpixmap->pixmap = NULL; + GST_DEBUG_OBJECT (evaspixmapsink,"Free pixmap"); + } + XFreeGC (evaspixmapsink->xcontext->disp, evaspixmapsink->xpixmap->gc); + XSync (evaspixmapsink->xcontext->disp, FALSE); + } + + /* Set pixmap id and create GC */ + evaspixmapsink->xpixmap->pixmap = pixmap_id; + evaspixmapsink->xpixmap->gc = XCreateGC(dpy, evaspixmapsink->xpixmap->pixmap, 0,0); + XSetForeground(dpy, evaspixmapsink->xpixmap->gc,evaspixmapsink->xcontext->black); + XFillRectangle(dpy, evaspixmapsink->xpixmap->pixmap, evaspixmapsink->xpixmap->gc, 0, 0, xw, xh); + XSync(dpy, FALSE); + + /* Create XDamage */ + if (evaspixmapsink->damage) { + GST_DEBUG_OBJECT (evaspixmapsink,"destroy former damage(%d)",evaspixmapsink->damage); + XDamageDestroy(evaspixmapsink->xcontext->disp, evaspixmapsink->damage); + evaspixmapsink->damage = NULL; + } + evaspixmapsink->damage = XDamageCreate (dpy, evaspixmapsink->xpixmap->pixmap, XDamageReportRawRectangles); + + /* Set flag for mapping evas object with xpixmap */ + evaspixmapsink->do_link = TRUE; + ecore_pipe_write(evaspixmapsink->epipe, evaspixmapsink, sizeof(GstEvasPixmapSink)); + + gst_evaspixmapsink_update_colorbalance (evaspixmapsink); + + g_mutex_unlock (evaspixmapsink->x_lock); + g_mutex_unlock (evaspixmapsink->flow_lock); + + return TRUE; + +GO_OUT_OF_FUNC: + g_mutex_unlock (evaspixmapsink->x_lock); + g_mutex_unlock (evaspixmapsink->flow_lock); + return FALSE; +} + +static void +gst_evaspixmapsink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstEvasPixmapSink *evaspixmapsink; + g_return_if_fail (GST_IS_EVASPIXMAPSINK (object)); + evaspixmapsink = GST_EVASPIXMAPSINK (object); + + Evas_Object *eo; + + switch (prop_id) { + case PROP_HUE: + evaspixmapsink->hue = g_value_get_int (value); + evaspixmapsink->cb_changed = TRUE; + gst_evaspixmapsink_update_colorbalance (evaspixmapsink); + break; + case PROP_CONTRAST: + evaspixmapsink->contrast = g_value_get_int (value); + evaspixmapsink->cb_changed = TRUE; + gst_evaspixmapsink_update_colorbalance (evaspixmapsink); + break; + case PROP_BRIGHTNESS: + evaspixmapsink->brightness = g_value_get_int (value); + evaspixmapsink->cb_changed = TRUE; + gst_evaspixmapsink_update_colorbalance (evaspixmapsink); + break; + case PROP_SATURATION: + evaspixmapsink->saturation = g_value_get_int (value); + evaspixmapsink->cb_changed = TRUE; + gst_evaspixmapsink_update_colorbalance (evaspixmapsink); + break; + case PROP_DISPLAY: + evaspixmapsink->display_name = g_strdup (g_value_get_string (value)); + break; + case PROP_SYNCHRONOUS: + evaspixmapsink->synchronous = g_value_get_boolean (value); + if (evaspixmapsink->xcontext) { + XSynchronize (evaspixmapsink->xcontext->disp, evaspixmapsink->synchronous); + GST_DEBUG_OBJECT (evaspixmapsink,"XSynchronize called with %s", evaspixmapsink->synchronous ? "TRUE" : "FALSE"); + } + break; + case PROP_PIXEL_ASPECT_RATIO: + g_free (evaspixmapsink->par); + evaspixmapsink->par = g_new0 (GValue, 1); + g_value_init (evaspixmapsink->par, GST_TYPE_FRACTION); + if (!g_value_transform (value, evaspixmapsink->par)) { + g_warning ("Could not transform string to aspect ratio"); + gst_value_set_fraction (evaspixmapsink->par, 1, 1); + } + GST_DEBUG_OBJECT (evaspixmapsink,"set PAR to %d/%d", gst_value_get_fraction_numerator (evaspixmapsink->par), gst_value_get_fraction_denominator (evaspixmapsink->par)); + break; + case PROP_FORCE_ASPECT_RATIO: + evaspixmapsink->keep_aspect = g_value_get_boolean (value); + break; + case PROP_DEVICE: + evaspixmapsink->adaptor_no = atoi (g_value_get_string (value)); + break; + case PROP_DOUBLE_BUFFER: + evaspixmapsink->double_buffer = g_value_get_boolean (value); + break; + case PROP_AUTOPAINT_COLORKEY: + evaspixmapsink->autopaint_colorkey = g_value_get_boolean (value); + break; + case PROP_COLORKEY: + evaspixmapsink->colorkey = g_value_get_int (value); + break; + case PROP_PIXMAP_WIDTH: + if (evaspixmapsink->xpixmap) { + evaspixmapsink->xpixmap->width = g_value_get_uint64 (value); + /* To do : code related to pixmap re-link */ + } + break; + case PROP_PIXMAP_HEIGHT: + if (evaspixmapsink->xpixmap) { + evaspixmapsink->xpixmap->height = g_value_get_uint64 (value); + /* To do : code related to pixmap re-link */ + } + break; +#ifdef GST_EXT_XV_ENHANCEMENT + case PROP_DISPLAY_GEOMETRY_METHOD: + evaspixmapsink->display_geometry_method = g_value_get_enum (value); + GST_INFO_OBJECT (evaspixmapsink,"Overlay geometry method update, display_geometry_method(%d)",evaspixmapsink->display_geometry_method); + if( evaspixmapsink->display_geometry_method != DISP_GEO_METHOD_FULL_SCREEN && + evaspixmapsink->display_geometry_method != DISP_GEO_METHOD_CROPPED_FULL_SCREEN ) { + if( evaspixmapsink->xcontext && evaspixmapsink->xpixmap ) { + g_mutex_lock( evaspixmapsink->flow_lock ); + gst_evaspixmapsink_xpixmap_clear (evaspixmapsink, evaspixmapsink->xpixmap); + g_mutex_unlock( evaspixmapsink->flow_lock ); + } + } + if (evaspixmapsink->xcontext) { + gst_evaspixmap_buffer_put (evaspixmapsink, evaspixmapsink->evas_pixmap_buf); + } + break; + case PROP_DST_ROI_X: + evaspixmapsink->dst_roi.x = g_value_get_int (value); + GST_INFO_OBJECT (evaspixmapsink, "ROI_X(%d)",evaspixmapsink->dst_roi.x ); + break; + case PROP_DST_ROI_Y: + evaspixmapsink->dst_roi.y = g_value_get_int (value); + GST_INFO_OBJECT (evaspixmapsink, "ROI_Y(%d)",evaspixmapsink->dst_roi.y ); + break; + case PROP_DST_ROI_W: + evaspixmapsink->dst_roi.w = g_value_get_int (value); + GST_INFO_OBJECT (evaspixmapsink, "ROI_W(%d)",evaspixmapsink->dst_roi.w ); + break; + case PROP_DST_ROI_H: + evaspixmapsink->dst_roi.h = g_value_get_int (value); + GST_INFO_OBJECT (evaspixmapsink, "ROI_H(%d)",evaspixmapsink->dst_roi.h ); + break; + case PROP_STOP_VIDEO: + evaspixmapsink->stop_video = g_value_get_int (value); + g_mutex_lock( evaspixmapsink->flow_lock ); + if( evaspixmapsink->stop_video ) { + GST_INFO_OBJECT (evaspixmapsink, "XPixmap CLEAR when set video-stop property" ); + gst_evaspixmapsink_xpixmap_clear (evaspixmapsink, evaspixmapsink->xpixmap); + } + g_mutex_unlock( evaspixmapsink->flow_lock ); + break; +#endif + case PROP_EVAS_OBJECT: + eo = g_value_get_pointer (value); + if ( is_evas_image_object (eo)) { + if (!evaspixmapsink->epipe) { + evaspixmapsink->epipe = ecore_pipe_add (ecore_pipe_callback_handler, evaspixmapsink); + if (!evaspixmapsink->epipe) { + GST_ERROR_OBJECT (evaspixmapsink,"Cannot set evas-object property: ecore_pipe_add() failed"); + break; + } + } + if (eo != evaspixmapsink->eo) { + /* delete evas object callbacks registrated on a former evas image object */ + evas_object_event_callback_del (evaspixmapsink->eo, EVAS_CALLBACK_DEL, evas_callback_del_event); + evas_object_event_callback_del (evaspixmapsink->eo, EVAS_CALLBACK_RESIZE, evas_callback_resize_event); + if (evaspixmapsink->eo) { + if (!gst_evaspixmapsink_xpixmap_link(evaspixmapsink)) { + GST_WARNING_OBJECT (evaspixmapsink,"link evas image object with pixmap failed..."); + return; + } + } + evaspixmapsink->eo = eo; + /* add evas object callbacks on a new evas image object */ + evas_object_event_callback_add (evaspixmapsink->eo, EVAS_CALLBACK_DEL, evas_callback_del_event, evaspixmapsink); + evas_object_event_callback_add (evaspixmapsink->eo, EVAS_CALLBACK_RESIZE, evas_callback_resize_event, evaspixmapsink); + GST_INFO_OBJECT (evaspixmapsink,"Evas Image Object(%x) is set", evaspixmapsink->eo); + } + } else { + GST_ERROR_OBJECT (evaspixmapsink,"Cannot set evas-object property: value is not an evas image object"); + } + break; + case PROP_VISIBLE: + evaspixmapsink->visible = g_value_get_boolean (value); + if (evaspixmapsink->eo) { + if (!evaspixmapsink->visible) { + if ( evaspixmapsink->xcontext && evaspixmapsink->xpixmap ) { + g_mutex_lock( evaspixmapsink->flow_lock ); + gst_evaspixmapsink_xpixmap_clear (evaspixmapsink, evaspixmapsink->xpixmap); + g_mutex_unlock( evaspixmapsink->flow_lock ); + } + evas_object_hide(evaspixmapsink->eo); + GST_INFO_OBJECT (evaspixmapsink,"object hide.."); + } else { + evas_object_show(evaspixmapsink->eo); + GST_INFO_OBJECT (evaspixmapsink,"object show.."); + } + } else { + GST_WARNING_OBJECT (evaspixmapsink,"evas image object was not set"); + } + break; + case PROP_ORIGIN_SIZE: + evaspixmapsink->use_origin_size = g_value_get_boolean (value); + GST_INFO_OBJECT (evaspixmapsink,"set origin-size (%d)",evaspixmapsink->use_origin_size); + if (evaspixmapsink->former_origin_size != evaspixmapsink->use_origin_size) { + if (!gst_evaspixmapsink_xpixmap_link(evaspixmapsink)) { + GST_WARNING_OBJECT (evaspixmapsink,"link evas image object with pixmap failed..."); + } + evaspixmapsink->former_origin_size = evaspixmapsink->use_origin_size; + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_evaspixmapsink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstEvasPixmapSink *evaspixmapsink; + + g_return_if_fail (GST_IS_EVASPIXMAPSINK (object)); + + evaspixmapsink = GST_EVASPIXMAPSINK (object); + + switch (prop_id) { + case PROP_HUE: + g_value_set_int (value, evaspixmapsink->hue); + break; + case PROP_CONTRAST: + g_value_set_int (value, evaspixmapsink->contrast); + break; + case PROP_BRIGHTNESS: + g_value_set_int (value, evaspixmapsink->brightness); + break; + case PROP_SATURATION: + g_value_set_int (value, evaspixmapsink->saturation); + break; + case PROP_DISPLAY: + g_value_set_string (value, evaspixmapsink->display_name); + break; + case PROP_SYNCHRONOUS: + g_value_set_boolean (value, evaspixmapsink->synchronous); + break; + case PROP_PIXEL_ASPECT_RATIO: + if (evaspixmapsink->par) { + if (!g_value_transform (evaspixmapsink->par, value)) { + g_warning ("g_value_transform() failure"); + } + } + break; + case PROP_FORCE_ASPECT_RATIO: + g_value_set_boolean (value, evaspixmapsink->keep_aspect); + break; + case PROP_DEVICE: + { + char *adaptor_no_s = g_strdup_printf ("%u", evaspixmapsink->adaptor_no); + g_value_set_string (value, adaptor_no_s); + g_free (adaptor_no_s); + break; + } + case PROP_DEVICE_NAME: + if (evaspixmapsink->xcontext && evaspixmapsink->xcontext->adaptors) { + g_value_set_string (value, + evaspixmapsink->xcontext->adaptors[evaspixmapsink->adaptor_no]); + } else { + g_value_set_string (value, NULL); + } + break; + case PROP_DOUBLE_BUFFER: + g_value_set_boolean (value, evaspixmapsink->double_buffer); + break; + case PROP_AUTOPAINT_COLORKEY: + g_value_set_boolean (value, evaspixmapsink->autopaint_colorkey); + break; + case PROP_COLORKEY: + g_value_set_int (value, evaspixmapsink->colorkey); + break; + case PROP_PIXMAP_WIDTH: + if (evaspixmapsink->xpixmap) { + g_value_set_uint64 (value, evaspixmapsink->xpixmap->width); + } else { + g_value_set_uint64 (value, 0); + } + break; + case PROP_PIXMAP_HEIGHT: + if (evaspixmapsink->xpixmap) { + g_value_set_uint64 (value, evaspixmapsink->xpixmap->height); + } else { + g_value_set_uint64 (value, 0); + } + break; +#ifdef GST_EXT_XV_ENHANCEMENT + case PROP_DISPLAY_GEOMETRY_METHOD: + g_value_set_enum (value, evaspixmapsink->display_geometry_method); + break; + case PROP_DST_ROI_X: + g_value_set_int (value, evaspixmapsink->dst_roi.x); + break; + case PROP_DST_ROI_Y: + g_value_set_int (value, evaspixmapsink->dst_roi.y); + break; + case PROP_DST_ROI_W: + g_value_set_int (value, evaspixmapsink->dst_roi.w); + break; + case PROP_DST_ROI_H: + g_value_set_int (value, evaspixmapsink->dst_roi.h); + break; + case PROP_STOP_VIDEO: + g_value_set_int (value, evaspixmapsink->stop_video); + break; +#endif + case PROP_EVAS_OBJECT: + g_value_set_pointer (value, evaspixmapsink->eo); + break; + case PROP_VISIBLE: + g_value_set_boolean (value, evaspixmapsink->visible); + break; + case PROP_ORIGIN_SIZE: + g_value_set_boolean (value, evaspixmapsink->use_origin_size); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_evaspixmapsink_reset (GstEvasPixmapSink *evaspixmapsink) +{ + GST_DEBUG_OBJECT (evaspixmapsink,"[START]"); + + GThread *thread; + GST_OBJECT_LOCK (evaspixmapsink); + evaspixmapsink->running = FALSE; + + /* grab thread and mark it as NULL */ + thread = evaspixmapsink->event_thread; + evaspixmapsink->event_thread = NULL; + GST_OBJECT_UNLOCK (evaspixmapsink); + + /* Wait for our event thread to finish before we clean up our stuff. */ + if (thread) { + g_thread_join (thread); + } + + if(evaspixmapsink->damage) { + XDamageDestroy(evaspixmapsink->xcontext->disp, evaspixmapsink->damage); + evaspixmapsink->damage = NULL; + } + if(evaspixmapsink->handler) { + ecore_event_handler_del (evaspixmapsink->handler); + evaspixmapsink->handler = NULL; + } + + evas_object_event_callback_del (evaspixmapsink->eo, EVAS_CALLBACK_RESIZE, evas_callback_resize_event); + evas_object_event_callback_del (evaspixmapsink->eo, EVAS_CALLBACK_DEL, evas_callback_del_event); + + if (evaspixmapsink->evas_pixmap_buf) { + g_boxed_free(GST_TYPE_EVASPIXMAP_BUFFER, evaspixmapsink->evas_pixmap_buf); + evaspixmapsink->evas_pixmap_buf = NULL; + } + if (evaspixmapsink->xpixmap) { + gst_evaspixmapsink_xpixmap_clear (evaspixmapsink, evaspixmapsink->xpixmap); + gst_evaspixmapsink_xpixmap_destroy (evaspixmapsink, evaspixmapsink->xpixmap); + evaspixmapsink->xpixmap = NULL; + if (evaspixmapsink->eo) { + evas_object_image_native_surface_set(evaspixmapsink->eo, NULL); + evaspixmapsink->eo = NULL; + } + } + evaspixmapsink->render_rect.x = evaspixmapsink->render_rect.y = + evaspixmapsink->render_rect.w = evaspixmapsink->render_rect.h = 0; + evaspixmapsink->have_render_rect = FALSE; + + gst_evaspixmapsink_xcontext_clear (evaspixmapsink); + + GST_DEBUG_OBJECT (evaspixmapsink,"[END]"); +} + +/* Finalize is called only once, dispose can be called multiple times. + * We use mutexes and don't reset stuff to NULL here so let's register + * as a finalize. */ +static void +gst_evaspixmapsink_finalize (GObject *object) +{ + GstEvasPixmapSink *evaspixmapsink; + evaspixmapsink = GST_EVASPIXMAPSINK (object); + GST_DEBUG_OBJECT (evaspixmapsink,"[START]"); + + if (evaspixmapsink->display_name) { + g_free (evaspixmapsink->display_name); + evaspixmapsink->display_name = NULL; + } + if (evaspixmapsink->par) { + g_free (evaspixmapsink->par); + evaspixmapsink->par = NULL; + } + if (evaspixmapsink->x_lock) { + g_mutex_free (evaspixmapsink->x_lock); + evaspixmapsink->x_lock = NULL; + } + if (evaspixmapsink->flow_lock) { + g_mutex_free (evaspixmapsink->flow_lock); + evaspixmapsink->flow_lock = NULL; + } + if (evaspixmapsink->epipe) { + ecore_pipe_del (evaspixmapsink->epipe); + evaspixmapsink->epipe = NULL; + } + + GST_DEBUG_OBJECT (evaspixmapsink,"[END]"); + + G_OBJECT_CLASS (parent_class)->finalize (object); + +} + +static void +gst_evaspixmapsink_init (GstEvasPixmapSink *evaspixmapsink) +{ + evaspixmapsink->display_name = NULL; + evaspixmapsink->adaptor_no = 0; + evaspixmapsink->xcontext = NULL; + evaspixmapsink->xpixmap = NULL; + evaspixmapsink->evas_pixmap_buf = NULL; + + evaspixmapsink->hue = evaspixmapsink->saturation = 0; + evaspixmapsink->contrast = evaspixmapsink->brightness = 0; + evaspixmapsink->cb_changed = FALSE; + + evaspixmapsink->fps_n = 0; + evaspixmapsink->fps_d = 0; + evaspixmapsink->video_width = 0; + evaspixmapsink->video_height = 0; + + evaspixmapsink->x_lock = g_mutex_new (); + evaspixmapsink->flow_lock = g_mutex_new (); + + evaspixmapsink->synchronous = FALSE; + evaspixmapsink->double_buffer = TRUE; + evaspixmapsink->keep_aspect = FALSE; + evaspixmapsink->par = NULL; + evaspixmapsink->autopaint_colorkey = TRUE; + evaspixmapsink->running = FALSE; + + /* on 16bit displays this becomes r,g,b = 1,2,3 + * on 24bit displays this becomes r,g,b = 8,8,16 + * as a port atom value + */ + evaspixmapsink->colorkey = (8 << 16) | (8 << 8) | 16; + +#ifdef GST_EXT_XV_ENHANCEMENT + evaspixmapsink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD; + evaspixmapsink->dst_roi.x = 0; + evaspixmapsink->dst_roi.y = 0; + evaspixmapsink->dst_roi.w = 0; + evaspixmapsink->dst_roi.h = 0; + evaspixmapsink->scr_w = 0; + evaspixmapsink->scr_h = 0; + evaspixmapsink->aligned_width = 0; + evaspixmapsink->aligned_height = 0; +#endif + evaspixmapsink->stop_video = FALSE; + evaspixmapsink->eo = NULL; + evaspixmapsink->epipe = NULL; + evaspixmapsink->do_link = FALSE; + evaspixmapsink->visible = TRUE; + evaspixmapsink->use_origin_size = FALSE; + evaspixmapsink->former_origin_size = FALSE; + + } + +static void +gst_evaspixmapsink_base_init (gpointer g_class) +{ +} + +static void +gst_evaspixmapsink_class_init (GstEvasPixmapSinkClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSinkClass *gstbasesink_class; + GstVideoSinkClass *videosink_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasesink_class = (GstBaseSinkClass *) klass; + videosink_class = (GstVideoSinkClass *) klass; + + parent_class = g_type_class_peek_parent (klass); + + gobject_class->set_property = gst_evaspixmapsink_set_property; + gobject_class->get_property = gst_evaspixmapsink_get_property; + + g_object_class_install_property (gobject_class, PROP_CONTRAST, + g_param_spec_int ("contrast", "Contrast", "The contrast of the video", + -1000, 1000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_BRIGHTNESS, + g_param_spec_int ("brightness", "Brightness", + "The brightness of the video", -1000, 1000, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_HUE, + g_param_spec_int ("hue", "Hue", "The hue of the video", -1000, 1000, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_SATURATION, + g_param_spec_int ("saturation", "Saturation", + "The saturation of the video", -1000, 1000, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_DISPLAY, + g_param_spec_string ("display", "Display", "X Display name", NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_SYNCHRONOUS, + g_param_spec_boolean ("synchronous", "Synchronous", + "When enabled, runs " + "the X display in synchronous mode. (used only for debugging)", FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO, + g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio", + "The pixel aspect ratio of the device", "1/1", + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO, + g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio", + "When enabled, scaling will respect original aspect ratio", FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_DEVICE, + g_param_spec_string ("device", "Adaptor number", + "The number of the video adaptor", "0", + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_DEVICE_NAME, + g_param_spec_string ("device-name", "Adaptor name", + "The name of the video adaptor", NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + /** + * GstEvasPixmapSink:double-buffer + * + * Whether to double-buffer the output. + * + * Since: 0.10.14 + */ + g_object_class_install_property (gobject_class, PROP_DOUBLE_BUFFER, + g_param_spec_boolean ("double-buffer", "Double-buffer", + "Whether to double-buffer the output", TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstEvasPixmapSink:autopaint-colorkey + * + * Whether to autofill overlay with colorkey + * + * Since: 0.10.21 + */ + g_object_class_install_property (gobject_class, PROP_AUTOPAINT_COLORKEY, + g_param_spec_boolean ("autopaint-colorkey", "Autofill with colorkey", + "Whether to autofill overlay with colorkey", TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstEvasPixmapSink:colorkey + * + * Color to use for the overlay mask. + * + * Since: 0.10.21 + */ + g_object_class_install_property (gobject_class, PROP_COLORKEY, + g_param_spec_int ("colorkey", "Colorkey", + "Color to use for the overlay mask", G_MININT, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstEvasPixmapSink:pixmap-width + * + * Actual width of the pixmap. + */ + g_object_class_install_property (gobject_class, PROP_PIXMAP_WIDTH, + g_param_spec_uint64 ("pixmap-width", "pixmap-width", "Width of the pixmap", 0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + /** + * GstEvasPixmapSink:pixmap-height + * + * Actual height of the pixmap. + */ + g_object_class_install_property (gobject_class, PROP_PIXMAP_HEIGHT, + g_param_spec_uint64 ("pixmap-height", "pixmap-height", "Height of the pixmap", 0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + +#ifdef GST_EXT_XV_ENHANCEMENT + /** + * GstEvasPixmapSink:display-geometry-method + * + * Display geometrical method setting + */ + g_object_class_install_property(gobject_class, PROP_DISPLAY_GEOMETRY_METHOD, + g_param_spec_enum("display-geometry-method", "Display geometry method", + "Geometrical method for display", + GST_TYPE_EVASPIXMAPSINK_DISPLAY_GEOMETRY_METHOD, DEF_DISPLAY_GEOMETRY_METHOD, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstEvasPixmapSink:dst-roi-x + * + * X value of Destination ROI + */ + g_object_class_install_property (gobject_class, PROP_DST_ROI_X, + g_param_spec_int ("dst-roi-x", "Dst-ROI-X", + "X value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstEvasPixmapSink:dst-roi-y + * + * Y value of Destination ROI + */ + g_object_class_install_property (gobject_class, PROP_DST_ROI_Y, + g_param_spec_int ("dst-roi-y", "Dst-ROI-Y", + "Y value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstEvasPixmapSink:dst-roi-w + * + * W value of Destination ROI + */ + g_object_class_install_property (gobject_class, PROP_DST_ROI_W, + g_param_spec_int ("dst-roi-w", "Dst-ROI-W", + "W value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_WIDTH, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstEvasPixmapSink:dst-roi-h + * + * H value of Destination ROI + */ + g_object_class_install_property (gobject_class, PROP_DST_ROI_H, + g_param_spec_int ("dst-roi-h", "Dst-ROI-H", + "H value of Destination ROI(only effective \"CUSTOM_ROI\")", 0, XV_SCREEN_SIZE_HEIGHT, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstEvasPixmapSink:stop-video + * + * Stop video for releasing video source buffer + */ + g_object_class_install_property (gobject_class, PROP_STOP_VIDEO, + g_param_spec_int ("stop-video", "Stop-Video", "Stop video for releasing video source buffer", 0, 1, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +#endif + + /** + * GstEvasPixmapSink:evas-object + * + * Evas image object for rendering + */ + g_object_class_install_property (gobject_class, PROP_EVAS_OBJECT, + g_param_spec_pointer ("evas-object", "Destination Evas Object", "Destination evas image object", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstEvasPixmapSink:visible + * + * visible setting for a evas image object + */ + g_object_class_install_property (gobject_class, PROP_VISIBLE, + g_param_spec_boolean ("visible", "Visible", "When setting it false, evas image object does not show", TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstEvasPixmapSink:origin-size + * + * Set pixmap size with media source's width and height + */ + g_object_class_install_property (gobject_class, PROP_ORIGIN_SIZE, + g_param_spec_boolean ("origin-size", "Origin-Size", "When setting it true, pixmap will be created with media source's width and height", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gobject_class->finalize = gst_evaspixmapsink_finalize; + + gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_change_state); + gst_element_class_set_details_simple (gstelement_class, + "EvasPixmapSink", "Sink/Video", + "evas image object videosink based on Xv extension", "Sangchul Lee "); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_evaspixmapsink_sink_template_factory)); + gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_getcaps); + gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_setcaps); + gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_get_times); + gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_event); + videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_evaspixmapsink_show_frame); +} + +/* Object typing & Creation */ + +static gboolean +plugin_init (GstPlugin *plugin) +{ + if (!gst_element_register (plugin, "evaspixmapsink", GST_RANK_NONE, GST_TYPE_EVASPIXMAPSINK)) { + return FALSE; + } + GST_DEBUG_CATEGORY_INIT (gst_debug_evaspixmapsink, "evaspixmapsink", 0, "evaspixmapsink element"); + GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE"); + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, + evaspixmapsink,"Evas image object render plugin using Xv extension", plugin_init, + VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/evaspixmapsink/evaspixmapsink.h b/evaspixmapsink/evaspixmapsink.h new file mode 100755 index 0000000..22ca115 --- /dev/null +++ b/evaspixmapsink/evaspixmapsink.h @@ -0,0 +1,388 @@ +/* + * EvasPixmapSink + * + * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Sangchul Lee + * + * 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_EVASPIXMAPSINK_H__ +#define __GST_EVASPIXMAPSINK_H__ + +#include + +#ifdef HAVE_XSHM +#include +#include +#include +#endif /* HAVE_XSHM */ + +#include +#include + +#ifdef HAVE_XSHM +#include +#endif /* HAVE_XSHM */ + +#include +#include +#include +#include +#ifdef GST_EXT_XV_ENHANCEMENT +#include +#include +#endif + +#include +#include +#include + +#include +#include +#include + +#define MAX_PLANE_NUM 3 +#define MAX_BUFFER_NUM 20 +#define MAX_GEM_BUFFER_NUM (MAX_PLANE_NUM * MAX_BUFFER_NUM) +typedef struct _gem_info_t { + int dmabuf_fd; + unsigned int gem_handle; + unsigned int gem_name; +} gem_info_t; + + +G_BEGIN_DECLS + +#define GST_TYPE_EVASPIXMAPSINK \ + (gst_evaspixmapsink_get_type()) +#define GST_EVASPIXMAPSINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_EVASPIXMAPSINK, GstEvasPixmapSink)) +#define GST_EVASPIXMAPSINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_EVASPIXMAPSINK, GstEvasPixmapSinkClass)) +#define GST_IS_EVASPIXMAPSINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_EVASPIXMAPSINK)) +#define GST_IS_EVASPIXMAPSINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_EVASPIXMAPSINK)) + +#ifdef GST_EXT_XV_ENHANCEMENT +#define XV_SCREEN_SIZE_WIDTH 4096 +#define XV_SCREEN_SIZE_HEIGHT 4096 +#endif /* GST_EXT_XV_ENHANCEMENT */ +#define MARGIN_OF_ERROR 0.005 + +typedef struct _GstXContext GstXContext; +typedef struct _GstXPixmap GstXPixmap; +typedef struct _GstEvasPixmapFormat GstEvasPixmapFormat; +typedef struct _GstEvasPixmapBuffer GstEvasPixmapBuffer; +typedef struct _GstEvasPixmapBufferClass GstEvasPixmapBufferClass; +typedef struct _GstEvasPixmapSink GstEvasPixmapSink; +typedef struct _GstEvasPixmapSinkClass GstEvasPixmapSinkClass; + +/* + * GstXContext: + * @disp: the X11 Display of this context + * @screen: the default Screen of Display @disp + * @screen_num: the Screen number of @screen + * @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: the pixel aspect ratio 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 + * @xv_port_id: the XVideo port ID + * @im_format: used to store at least a valid format for XShm calls checks + * @formats_list: list of supported image formats on @xv_port_id + * @channels_list: list of #GstColorBalanceChannels + * @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; + gint screen_num; + + Visual *visual; + + Window root; + + gulong white, black; + + gint depth; + gint bpp; + gint endianness; + + gint width, height; + gint widthmm, heightmm; + GValue *par; /* calculated pixel aspect ratio */ + + gboolean use_xshm; + + XvPortID xv_port_id; + guint nb_adaptors; + gchar ** adaptors; + guint32 im_format; + + GList *formats_list; + GList *channels_list; + + GstCaps *caps; +}; + +/* + * GstXPixmap: + * @pixmap: the pixmap ID of this X11 pixmap + * @width: the width in pixels of Pixmap @pixmap + * @height: the height in pixels of Pixmap @pixmap + * @gc: the Graphical Context of Pixmap @pixmap + * + * Structure used to store informations about a Pixmap. + */ +struct _GstXPixmap { + Pixmap pixmap; +#ifdef GST_EXT_XV_ENHANCEMENT + gint x, y; +#endif + gint width, height; + GC gc; +}; + +/** + * GstEvasPixmapFormat: + * @format: the image format + * @caps: generated #GstCaps for this image format + * + * Structure storing image format to #GstCaps association. + */ +struct _GstEvasPixmapFormat { + guint32 format; + GstCaps *caps; +}; + +/** + * GstEvasPixmapBuffer: + * @evaspixmapsink: a reference to our #GstEvasPixmapSink + * @xvimage: the XvImage of this buffer + * @width: the width in pixels of XvImage @xvimage + * @height: the height in pixels of XvImage @xvimage + * @im_format: the image format of XvImage @xvimage + * @size: the size in bytes of XvImage @xvimage + * + * Subclass of #GstBuffer containing additional information about an XvImage. + */ +struct _GstEvasPixmapBuffer { + GstBuffer* buffer; + + /* Reference to the evaspixmapsink we belong to */ + GstEvasPixmapSink *evaspixmapsink; + XvImage *xvimage; + +#ifdef HAVE_XSHM + XShmSegmentInfo SHMInfo; +#endif /* HAVE_XSHM */ + + gint width, height; + guint32 im_format; + size_t size; +}; + +/** + * GstEvasPixmapSink: + * @display_name: the name of the Display we want to render to + * @xcontext: our instance's #GstXContext + * @xpixmap: the #GstXPixmap we are rendering to + * @fps_n: the framerate fraction numerator + * @fps_d: the framerate fraction denominator + * @x_lock: used to protect X calls as we are not using the XLib in threaded + * mode + * @flow_lock: used to protect data flow routines from external calls such as + * methods from the #GstXOverlay interface + * @par: used to override calculated pixel aspect ratio from @xcontext + * @synchronous: used to store if XSynchronous should be used or not (for + * debugging purpose only) + * @keep_aspect: used to remember if reverse negotiation scaling should respect + * aspect ratio + * @brightness: used to store the user settings for color balance brightness + * @contrast: used to store the user settings for color balance contrast + * @hue: used to store the user settings for color balance hue + * @saturation: used to store the user settings for color balance saturation + * @cb_changed: used to store if the color balance settings where changed + * @video_width: the width of incoming video frames in pixels + * @video_height: the height of incoming video frames in pixels + * + * The #GstEvasPixmapSink data structure. + */ +struct _GstEvasPixmapSink { + /* Our element stuff */ + GstVideoSink videosink; + + char *display_name; + guint adaptor_no; + + GstXContext *xcontext; + GstXPixmap *xpixmap; + GstEvasPixmapBuffer *evas_pixmap_buf; + + GThread *event_thread; + gboolean running; + + gint fps_n; + gint fps_d; + + GMutex *x_lock; + GMutex *flow_lock; + + /* object-set pixel aspect ratio */ + GValue *par; + + gboolean synchronous; + gboolean double_buffer; + gboolean keep_aspect; + + gint brightness; + gint contrast; + gint hue; + gint saturation; + gboolean cb_changed; + + /* size of incoming video, used as the size for XvImage */ + guint video_width, video_height; + + /* display sizes, used for clipping the image */ + gint disp_x, disp_y; + gint disp_width, disp_height; + + /* port attributes */ + gboolean autopaint_colorkey; + gint colorkey; + + /* port features */ + gboolean have_autopaint_colorkey; + gboolean have_colorkey; + gboolean have_double_buffer; + + /* target video rectagle */ + GstVideoRectangle render_rect; + gboolean have_render_rect; + +#ifdef GST_EXT_XV_ENHANCEMENT + /* display */ + guint display_geometry_method; + GstVideoRectangle dst_roi; + guint scr_w, scr_h; + /* needed if fourcc is one if S series */ + guint aligned_width; + guint aligned_height; + GstCaps *negotiated_caps; +#endif + gboolean stop_video; + + /* evas object */ + Evas_Object *eo; + Evas_Coord w; + Evas_Coord h; + gboolean visible; + + /* pixmap */ + gboolean do_link; + gboolean use_origin_size; + gboolean former_origin_size; + + /* damage event */ + Damage damage; + int damage_case; + Ecore_Event_Handler *handler; + Ecore_Pipe *epipe; + + gint drm_fd; + gem_info_t gem_info[MAX_GEM_BUFFER_NUM]; +}; + +#ifdef GST_EXT_XV_ENHANCEMENT +/* max plane count *********************************************************/ +#define MPLANE_IMGB_MAX_COUNT (4) + +/* image buffer definition *************************************************** + + +------------------------------------------+ --- + | | ^ + | uaddr[], index[] | | + | +---------------------------+ --- | | + | | | ^ | | + | |<-------- width[] -------->| | | | + | | | | | | + | | | | + | | |height[]|elevation[] + | | | | + | | | | | | + | | | | | | + | | | v | | + | +---------------------------+ --- | | + | | v + +------------------------------------------+ --- + + |<----------------- stride[] ------------------>| +*/ +typedef struct _GstMultiPlaneImageBuffer GstMultiPlaneImageBuffer; +struct _GstMultiPlaneImageBuffer +{ + GstBuffer buffer; + + /* width of each image plane */ + gint width[MPLANE_IMGB_MAX_COUNT]; + /* height of each image plane */ + gint height[MPLANE_IMGB_MAX_COUNT]; + /* stride of each image plane */ + gint stride[MPLANE_IMGB_MAX_COUNT]; + /* elevation of each image plane */ + gint elevation[MPLANE_IMGB_MAX_COUNT]; + /* user space address of each image plane */ + gpointer uaddr[MPLANE_IMGB_MAX_COUNT]; + /* Index of real address of each image plane, if needs */ + gpointer index[MPLANE_IMGB_MAX_COUNT]; + /* left postion, if needs */ + gint x; + /* top position, if needs */ + gint y; + /* to align memory */ + gint __dummy2; + /* arbitrary data */ + gint data[16]; +}; +#endif /* GST_EXT_XV_ENHANCEMENT */ + +struct _GstEvasPixmapSinkClass { + GstVideoSinkClass parent_class; +}; + +GType gst_evaspixmapsink_get_type(void); + +G_END_DECLS + +#endif /* __GST_EVASPIXMAPSINK_H__ */ diff --git a/evaspixmapsink/xv_types.h b/evaspixmapsink/xv_types.h new file mode 100644 index 0000000..9ed7939 --- /dev/null +++ b/evaspixmapsink/xv_types.h @@ -0,0 +1,41 @@ +/* */ +/* File name : xv_types.h */ +/* Author : YoungHoon Jung (yhoon.jung@samsung.com) */ +/* Protocol Version : 1.0.1 (Dec 16th 2009) */ +/* This file is for describing Xv APIs' buffer encoding method. */ +/* */ + +#define XV_PUTIMAGE_HEADER 0xDEADCD01 +#define XV_PUTIMAGE_VERSION 0x00010001 + +/* Return Values */ +#define XV_OK 0 +#define XV_HEADER_ERROR -1 +#define XV_VERSION_MISMATCH -2 + +/* Video Mode */ +#define VIDEO_MODE_TV_LCD 1 +#define VIDEO_MODE_TVONLY 2 +#define VIDEO_MODE_LCDONLY 3 +#define VIDEO_MODE_TVCAPTION 4 + +/* Buffer Type */ +#define XV_BUF_TYPE_DMABUF 0 +#define XV_BUF_TYPE_LEGACY 1 + +/* Data structure for XvPutImage / XvShmPutImage */ +typedef struct { + unsigned int _header; /* for internal use only */ + unsigned int _version; /* for internal use only */ + + unsigned int YBuf; + unsigned int CbBuf; + unsigned int CrBuf; + unsigned int BufType; +} XV_PUTIMAGE_DATA, * XV_PUTIMAGE_DATA_PTR; + +static void XV_PUTIMAGE_INIT_DATA(XV_PUTIMAGE_DATA_PTR data) +{ + data->_header = XV_PUTIMAGE_HEADER; + data->_version = XV_PUTIMAGE_VERSION; +} diff --git a/fimcconvert/Makefile.am b/fimcconvert/Makefile.am new file mode 100755 index 0000000..5e1c07c --- /dev/null +++ b/fimcconvert/Makefile.am @@ -0,0 +1,15 @@ +# Copyright (c) 2006 Software Laboratory, SAMSUNG Electronics, Inc. +# All rights reserved. +# +# This software is the confidential and proprietary information of +# SAMSUNG Electronics, Inc. ("Confidential Information"). +# You shall not disclose such Confidential Information and shall use it +# only in accordance with the terms of the license agreement you entered into +# with SAMSUNG Electronics. +# +# Orignal by Jin-mook Lim +# Bum-seok Lee +# Created by Jaekyun Lee +# Midefied by Jeechul jeon + +SUBDIRS = src diff --git a/fimcconvert/src/Makefile.am b/fimcconvert/src/Makefile.am new file mode 100755 index 0000000..cc34d3b --- /dev/null +++ b/fimcconvert/src/Makefile.am @@ -0,0 +1,27 @@ +# plugindir is set in configure + +############################################################################## +# change libgstplugin.la to something more suitable, e.g. libmysomething.la # +############################################################################## +plugin_LTLIBRARIES = libgstfimcconvert.la + +############################################################################## +# for the next set of variables, rename the prefix if you renamed the .la, # +# e.g. libgstplugin_la_SOURCES => libmysomething_la_SOURCES # +# libgstplugin_la_CFLAGS => libmysomething_la_CFLAGS # +# libgstplugin_la_LIBADD => libmysomething_la_LIBADD # +# libgstplugin_la_LDFLAGS => libmysomething_la_LDFLAGS # +############################################################################## + +# sources used to compile this plug-in +libgstfimcconvert_la_SOURCES = gstfimcconvert.c fimc_drm_api.c + +# flags used to compile this plugin +# add other _CFLAGS and _LIBS as needed +libgstfimcconvert_la_CFLAGS = $(GST_CFLAGS) $(GST_VIDEO_CFLAGS) $(DRM_CFLAGS) $(XFIXES_CFLAGS) $(DRI2PROTO_CFLAGS) $(DRI2_CFLAGS) $(TBM_CFLAGS) +libgstfimcconvert_la_LIBADD = $(GST_LIBS) $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_VIDEO_LIBS) $(DRM_LIBS) $(XFIXES_LIBS) $(DRI2PROTO_LIBS) $(DRI2_LIBS) $(TBM_LIBS) +libgstfimcconvert_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +# headers we need but don't want installed +noinst_HEADERS = gstfimcconvert.h fimc_drm_api.h + diff --git a/fimcconvert/src/fimc_drm_api.c b/fimcconvert/src/fimc_drm_api.c new file mode 100755 index 0000000..7c86113 --- /dev/null +++ b/fimcconvert/src/fimc_drm_api.c @@ -0,0 +1,412 @@ + /* + * FimcConvert + * + * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Sangchul Lee , Eunchul Kim + * + * 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 "fimc_drm_api.h" + +int +exynos_drm_ipp_set_property(int fd, + struct drm_exynos_ipp_property *property, + struct drm_exynos_sz *src_sz, struct drm_exynos_sz *dst_sz, + uint32_t src_format, uint32_t dst_format, + enum drm_exynos_ipp_cmd cmd, + enum drm_exynos_degree dst_degree, enum drm_exynos_flip dst_flip) +{ + struct drm_exynos_pos src_crop_pos = {0, 0, src_sz->hsize, src_sz->vsize}; + struct drm_exynos_pos dst_crop_pos = {0, 0, dst_sz->hsize, dst_sz->vsize}; + int ret = 0; + + if(!property) { + GST_ERROR("invalid argument, property is null.."); + return -1; + } + + memset(property, 0x00, sizeof(struct drm_exynos_ipp_property)); + property->cmd = cmd; + + switch(cmd) { + case IPP_CMD_M2M: + property->config[EXYNOS_DRM_OPS_SRC].ops_id = EXYNOS_DRM_OPS_SRC; + property->config[EXYNOS_DRM_OPS_SRC].flip = EXYNOS_DRM_FLIP_NONE; + property->config[EXYNOS_DRM_OPS_SRC].degree = EXYNOS_DRM_DEGREE_0; + property->config[EXYNOS_DRM_OPS_SRC].fmt = src_format; + property->config[EXYNOS_DRM_OPS_SRC].pos = src_crop_pos; + property->config[EXYNOS_DRM_OPS_SRC].sz = *src_sz; + + property->config[EXYNOS_DRM_OPS_DST].ops_id = EXYNOS_DRM_OPS_DST; + property->config[EXYNOS_DRM_OPS_DST].flip = dst_flip; + property->config[EXYNOS_DRM_OPS_DST].degree = dst_degree; + property->config[EXYNOS_DRM_OPS_DST].fmt = dst_format; + + /* Bit alignment for IPP : DST */ + switch (dst_format) { + case DRM_FORMAT_NV12MT: + dst_sz->hsize = ALIGN_TO_16B(dst_sz->hsize); + dst_sz->vsize = ALIGN_TO_8B(dst_sz->vsize); + break; + case DRM_FORMAT_NV12: + /* NOTE: for H/W encoder issue, use ALIGN */ + dst_sz->hsize = ALIGN_TO_16B(dst_sz->hsize); + dst_sz->vsize = ALIGN_TO_16B(dst_sz->vsize); + dst_crop_pos.w = ALIGN_TO_2B(dst_sz->hsize); + break; + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_BGRX8888: + case DRM_FORMAT_BGRA8888: + dst_sz->vsize = ALIGN_TO_4B(dst_sz->vsize); + break; + default: + dst_sz->hsize = ALIGN_TO_16B(dst_sz->hsize); + dst_sz->vsize = ALIGN_TO_2B(dst_sz->vsize); + break; + } + property->config[EXYNOS_DRM_OPS_DST].pos = dst_crop_pos; + property->config[EXYNOS_DRM_OPS_DST].sz = *dst_sz; + break; + + case IPP_CMD_WB: + case IPP_CMD_OUTPUT: + default: + ret = -EINVAL; + return ret; + } + + ret = ioctl(fd, DRM_IOCTL_EXYNOS_IPP_SET_PROPERTY, property); + if (ret) { + GST_ERROR("failed to DRM_IOCTL_EXYNOS_IPP_SET_PROPERTY : %s", strerror(errno)); + } + + GST_DEBUG("DRM_IOCTL_EXYNOS_IPP_SET_PROPERTY : prop_id[%d]", property->prop_id); + + return ret; +} + +int +exynos_drm_ipp_queue_buf(int fd, + enum drm_exynos_ops_id ops_id, + enum drm_exynos_ipp_buf_type buf_type, + int prop_id, + int buf_id, + uint32_t gem_handle_y, uint32_t gem_handle_cb, uint32_t gem_handle_cr) +{ + int ret = 0; + struct drm_exynos_ipp_queue_buf qbuf; + + memset(&qbuf, 0x00, sizeof(struct drm_exynos_ipp_queue_buf)); + + if (!gem_handle_y) { + GST_ERROR("invalid argument, gem_handle_y is null.."); + return -1; + } + + qbuf.ops_id = ops_id; + qbuf.buf_type = buf_type; + qbuf.user_data = 0; + qbuf.prop_id = prop_id; + qbuf.buf_id = buf_id; + qbuf.handle[EXYNOS_DRM_PLANAR_Y] = gem_handle_y; + qbuf.handle[EXYNOS_DRM_PLANAR_CB] = gem_handle_cb; + qbuf.handle[EXYNOS_DRM_PLANAR_CR] = gem_handle_cr; + + ret = ioctl(fd, DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF, &qbuf); + if (ret) { + GST_ERROR("failed to DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF[id:%d][buf_type:%d] : %s", ops_id, buf_type, strerror(errno)); + } + + return ret; +} + +int +exynos_drm_ipp_cmd_ctrl(int fd, int prop_id, enum drm_exynos_ipp_ctrl ctrl) +{ + int ret = 0; + struct drm_exynos_ipp_cmd_ctrl cmd_ctrl; + + memset(&cmd_ctrl, 0x00, sizeof(struct drm_exynos_ipp_cmd_ctrl)); + + cmd_ctrl.prop_id = prop_id; + cmd_ctrl.ctrl = ctrl; + + GST_DEBUG("prop_id(%d), ipp ctrl cmd(%d)", prop_id, ctrl); + ret = ioctl(fd, DRM_IOCTL_EXYNOS_IPP_CMD_CTRL, &cmd_ctrl); + if (ret) { + GST_ERROR("failed to DRM_IOCTL_EXYNOS_IPP_CMD_CTRL[prop_id:%d][ctrl:%d] : %s", prop_id, ctrl, strerror(errno)); + } + + return ret; +} + +int +fimcconvert_drm_create_gem(int drm_fimc_fd, struct drm_exynos_gem_create *gem) +{ + int ret = 0; + + if (drm_fimc_fd < 0) { + GST_ERROR("DRM is not opened"); + return -1; + } + if (!gem) { + GST_ERROR("gem is null.."); + return -1; + } + /* NOTE : structure gem should have its size */ +#ifdef USE_BO_TILED + if (!gem->gsize.size && gem->gsize.tiled.width && gem->gsize.tiled.height ) { + GST_ERROR("gem size is null.."); + return -1; + } +#else + if (!gem->size) { + GST_ERROR("gem size is null.."); + return -1; + } +#endif + +#ifdef USE_CACHABLE_GEM + gem->flags = EXYNOS_BO_CACHABLE | EXYNOS_BO_CONTIG; +#else + gem->flags = EXYNOS_BO_NONCACHABLE | EXYNOS_BO_CONTIG; +#endif + + ret = ioctl(drm_fimc_fd, DRM_IOCTL_EXYNOS_GEM_CREATE, gem); + if (ret < 0) { + GST_ERROR("failed to create gem buffer: %s", g_strerror (errno)); + return -1; + } + + GST_DEBUG("create drm gem handle(%d)", gem->handle); + + return 0; +} + +int +fimcconvert_gem_flush_cache(int drm_fimc_fd) +{ + int ret = 0; + struct drm_exynos_gem_cache_op cache_op; + + if (drm_fimc_fd < 0) { + GST_ERROR("DRM is not opened"); + return -1; + } + + cache_op.flags = 0; + cache_op.flags = (EXYNOS_DRM_ALL_CACHES_CORES | EXYNOS_DRM_CACHE_FSH_ALL); + + ret = ioctl (drm_fimc_fd, DRM_IOCTL_EXYNOS_GEM_CACHE_OP, &cache_op); + if (ret < 0) { + GST_ERROR("failed to gem cache op: %s", g_strerror (errno)); + return -1; + } + + GST_DEBUG("success to gem_flush_cache"); + + return 0; +} + +int +fimcconvert_drm_mmap_gem(int drm_fimc_fd, struct drm_exynos_gem_mmap *mmap) +{ + int ret = 0; + + if (drm_fimc_fd < 0) { + GST_ERROR("DRM is not opened"); + return -1; + } + if (!mmap) { + GST_ERROR("mmap is null.."); + return -1; + } + /* NOTE : structure mmap should have its size */ + if (!mmap->size) { + GST_ERROR("mmap size is null.."); + return -1; + } + + ret = ioctl(drm_fimc_fd, DRM_IOCTL_EXYNOS_GEM_MMAP, mmap); + if (ret < 0) { + GST_ERROR("failed to mmap gem: %s", g_strerror (errno)); + return -1; + } + + GST_DEBUG("mmapped addr(0x%x)", (void*)(unsigned long)mmap->mapped); + + return 0; +} + +void +fimcconvert_drm_close_gem(int drm_fimc_fd, unsigned int gem_handle) +{ + int ret = 0; + struct drm_gem_close close_arg = {0,}; + + if (drm_fimc_fd < 0) { + GST_ERROR("DRM is not opened"); + return; + } + if (gem_handle == 0) { + GST_ERROR("invalid gem_handle(%d)",gem_handle); + return; + } + + close_arg.handle = gem_handle; + ret = ioctl(drm_fimc_fd, DRM_IOCTL_GEM_CLOSE, &close_arg); + if (ret < 0) { + GST_ERROR("failed to DRM_IOCTL_GEM_CLOSE, gem handle(%d) : %s",gem_handle, g_strerror (errno)); + return; + } else { + GST_DEBUG("close drm gem handle(%d)", gem_handle); + } + + return; +} + +int +fimcconvert_drm_convert_fd_to_gemhandle(int drm_fimc_fd, int dmabuf_fd, uint32_t *gem_handle) +{ + int ret = 0; + struct drm_prime_handle prime_arg = {0,}; + + if (drm_fimc_fd < 0) { + GST_ERROR("DRM is not opened"); + return -1; + } + /* some planes may have fd value 0, but keep going.. */ + if (dmabuf_fd <= 0) { + GST_DEBUG("fd(%d) is not valid", dmabuf_fd); /* temporarily change log level to DEBUG for reducing WARNING level log */ + return 0; + } + + prime_arg.fd = dmabuf_fd; + ret = ioctl(drm_fimc_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime_arg); + if (ret<0) { + GST_ERROR("failed to DRM_IOCTL_PRIME_FD_TO_HANDLE, fd(%d): %s", dmabuf_fd, g_strerror (errno)); + return -1; + } + + GST_DEBUG("converted fd(%d) to gem_handle(%u)", dmabuf_fd, prime_arg.handle); + + *gem_handle = prime_arg.handle; + + return 0; +} + +int +fimcconvert_drm_convert_gemhandle_to_fd(int drm_fimc_fd, uint32_t gem_handle, int *dmabuf_fd) +{ + int ret = 0; + struct drm_prime_handle prime; + + if (drm_fimc_fd < 0) { + GST_ERROR("DRM is not opened"); + return -1; + } + if (gem_handle <= 0) { + GST_WARNING("gem_handle(%u) is not valid", gem_handle); + return 0; + } + + memset (&prime, 0, sizeof (struct drm_prime_handle)); + prime.handle = gem_handle; + ret = ioctl(drm_fimc_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime); + if (ret<0) { + GST_ERROR("failed to DRM_IOCTL_PRIME_HANDLE_TO_FD: %s", g_strerror (errno)); + return -1; + } + + GST_DEBUG("converted gem_handle(%u) to fd(%d)", gem_handle, prime.fd); + + *dmabuf_fd = prime.fd; + + return 0; +} + +int +fimcconvert_drm_gem_get_phy_addr(int drm_fimc_fd, uint32_t gem_handle, uint64_t *phy_addr) +{ + int ret = 0; + struct drm_exynos_gem_get_phy gem_dst_phy; + + if (drm_fimc_fd < 0) { + GST_ERROR("DRM is not opened"); + return -1; + } + if (gem_handle <= 0) { + GST_ERROR("gem_handle(%d) is not valid", gem_handle); + return -1; + } + + /* initialize structure for gem_get_phy */ + memset(&gem_dst_phy, 0x00, sizeof(struct drm_exynos_gem_get_phy)); + gem_dst_phy.gem_handle = gem_handle; + + ret = ioctl(drm_fimc_fd, DRM_IOCTL_EXYNOS_GEM_GET_PHY, &gem_dst_phy); + if (ret < 0) { + GST_ERROR("failed to get physical address: %s",g_strerror (errno)); + return -1; + } + + GST_DEBUG("gem_handle=%d, phy addr=0x%x", gem_handle, (void*)(unsigned long)gem_dst_phy.phy_addr); + + *phy_addr = gem_dst_phy.phy_addr; + + return 0; +} + +int +fimcconvert_drm_gem_import_phy_addr(int drm_fimc_fd, struct drm_exynos_gem_phy_imp *gem_phy_imp) +{ + int ret = 0; + + if (drm_fimc_fd < 0) { + GST_ERROR("DRM is not opened"); + return -1; + } + if (!gem_phy_imp) { + GST_ERROR("gem_phy_imp is null.."); + return -1; + } + + if (!gem_phy_imp->phy_addr) { + GST_ERROR("phy_addr is null.. can not execute DRM_IOCTL_EXYNOS_GEM_PHY_IMP"); + return -1; + } +#ifdef USE_BO_TILED + if (!gem_phy_imp->gsize.tiled.width || !gem_phy_img->gsize.tiled.height) { +#else + if (!gem_phy_imp->size) { +#endif + GST_ERROR("size if null..can not execute DRM_IOCTL_EXYNOS_GEM_PHY_IMP"); + return -1; + } + + ret = ioctl(drm_fimc_fd, DRM_IOCTL_EXYNOS_GEM_PHY_IMP, gem_phy_imp); + if (ret < 0) { + GST_ERROR("DRM_IOCTL_EXYNOS_GEM_PHY_IMP failed : %s",g_strerror (errno)); + return -1; + } + + GST_DEBUG("gem_handle=%d, phy addr=0x%x", gem_phy_imp->gem_handle, (void*)(unsigned long)gem_phy_imp->phy_addr); + + return 0; +} diff --git a/fimcconvert/src/fimc_drm_api.h b/fimcconvert/src/fimc_drm_api.h new file mode 100755 index 0000000..ecb9846 --- /dev/null +++ b/fimcconvert/src/fimc_drm_api.h @@ -0,0 +1,63 @@ +#ifndef __FIMC_H__ +#define __FIMC_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* headers for drm and gem */ +#include +#include +#include +#include +#include +#include +#include + +/* tbm */ +#include + +/* ioctl */ +#include + +GST_DEBUG_CATEGORY_EXTERN(fimcconvert_debug); +#define GST_CAT_DEFAULT fimcconvert_debug +//#define USE_CACHABLE_GEM + +#if 1 +/* 2 non contiguous plane YCbCr */ +#define fourcc_code(a,b,c,d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | \ + ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24)) +#define DRM_FORMAT_NV12M fourcc_code('N', 'M', '1', '2') /* 2x2 subsampled Cr:Cb plane */ +#define DRM_FORMAT_NV12MT fourcc_code('T', 'M', '1', '2') /* 2x2 subsampled Cr:Cb plane 64x32 macroblocks */ +#endif + +/* macro for align ***********************************************************/ +#define ALIGN_TO_2B(x) ((((x) + (1 << 1) - 1) >> 1) << 1) +#define ALIGN_TO_4B(x) ((((x) + (1 << 2) - 1) >> 2) << 2) +#define ALIGN_TO_8B(x) ((((x) + (1 << 3) - 1) >> 3) << 3) +#define ALIGN_TO_16B(x) ((((x) + (1 << 4) - 1) >> 4) << 4) +#define ALIGN_TO_32B(x) ((((x) + (1 << 5) - 1) >> 5) << 5) +#define ALIGN_TO_128B(x) ((((x) + (1 << 7) - 1) >> 7) << 7) +#define ALIGN_TO_2KB(x) ((((x) + (1 << 11) - 1) >> 11) << 11) +#define ALIGN_TO_8KB(x) ((((x) + (1 << 13) - 1) >> 13) << 13) +#define ALIGN_TO_64KB(x) ((((x) + (1 << 16) - 1) >> 16) << 16) + +int exynos_drm_ipp_set_property(int fd, struct drm_exynos_ipp_property *property, struct drm_exynos_sz *src_sz, struct drm_exynos_sz *dst_sz, uint32_t src_format, uint32_t dst_format, enum drm_exynos_ipp_cmd cmd, enum drm_exynos_degree degree, enum drm_exynos_flip flip); +int exynos_drm_ipp_queue_buf(int fd, enum drm_exynos_ops_id ops_id, enum drm_exynos_ipp_buf_type buf_type, int prop_id, int buf_id, uint32_t gem_handle_y, uint32_t gem_handle_cb, uint32_t gem_handle_cr); +int exynos_drm_ipp_cmd_ctrl(int fd, int prop_id, enum drm_exynos_ipp_ctrl ctrl); +int fimcconvert_drm_create_gem(int drm_fimc_fd, struct drm_exynos_gem_create *gem); +void fimcconvert_drm_close_gem(int drm_fimc_fd, unsigned int gem_handle); +int fimcconvert_drm_convert_fd_to_gemhandle(int drm_fimc_fd, int dmabuf_fd, uint32_t *gem_handle); +int fimcconvert_drm_convert_gemhandle_to_fd(int drm_fimc_fd, uint32_t gem_handle, int *dmabuf_fd); +int fimcconvert_drm_gem_get_phy_addr(int drm_fimc_fd, uint32_t gem_handle, uint64_t *phy_addr); +int fimcconvert_drm_gem_import_phy_addr(int drm_fimc_fd, struct drm_exynos_gem_phy_imp *gem_phy_imp); +int fimcconvert_drm_mmap_gem(int drm_fimc_fd, struct drm_exynos_gem_mmap *mmap); +int fimcconvert_gem_flush_cache(int drm_fimc_fd); +#endif diff --git a/fimcconvert/src/gstfimcconvert.c b/fimcconvert/src/gstfimcconvert.c new file mode 100755 index 0000000..f7f9aaa --- /dev/null +++ b/fimcconvert/src/gstfimcconvert.c @@ -0,0 +1,2717 @@ +/* + * FimcConvert + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. + * + * Contact: Sangchul Lee + * + * 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 + * + */ + +/*! Revision History: + *! ------------------------------------------------------------------------------------ + *! DATE | AUTHOR | COMMENTS + *! ------------------------------------------------------------------------------------ + *! 22-Sep-2010 naveen.ch@samsung.com + *! 02-Aug-2012 sc11.lee@samsung.com expand input/output colorspace formats + *! 15-Oct-2012 sc11.lee@samsung.com apply DRM-IPP interface + *! 24-Oct-2012 sc11.lee@samsung.com support DMA-BUF + *! 16-Mar-2013 sc11.lee@samsung.com support TBM + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstfimcconvert.h" + +#define DEBUG_FOR_DV + +#ifdef DEBUG_FOR_DV + int total_converted_frame_count = 0; + int total_buffer_unref_count = 0; +#endif + +/* debug variable definition */ +GST_DEBUG_CATEGORY(fimcconvert_debug); +#define GST_CAT_DEFAULT fimcconvert_debug + +enum +{ + PROP_0, + PROP_ROT_ANG, + PROP_DST_WIDTH, + PROP_DST_HEIGHT, + PROP_FLIP, + PROP_SRC_RANDOM_IDX, + PROP_DST_BUFFER_NUM, +}; + +typedef enum { + FIMCCONVERT_ROTATE_NONE = 0, + FIMCCONVERT_ROTATE_90 = 90, + FIMCCONVERT_ROTATE_180 = 180, + FIMCCONVERT_ROTATE_270 = 270 +} FIMCConvertRotateType; + +typedef enum { + FIMCCONVERT_FLIP_NONE = 0, + FIMCCONVERT_FLIP_VERTICAL, + FIMCCONVERT_FLIP_HORIZONTAL +} FIMCConvertFlipType; + +typedef enum { + FIMCCONVERT_GEM_FOR_SRC = 0, + FIMCCONVERT_GEM_FOR_DST = 1, +} FimcConvertGemCreateType; + +typedef enum { + FIMCCONVERT_IPP_CTRL_STOP = 0, + FIMCCONVERT_IPP_CTRL_START = 1, +} FimcConvertIppCtrl; + +static GstStaticPadTemplate sink_template = 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 ]; " \ + GST_VIDEO_CAPS_MAKE ("ST12") ";" \ + GST_VIDEO_CAPS_MAKE ("SN12") ";" \ + GST_VIDEO_CAPS_MAKE ("NV12") ";" \ + GST_VIDEO_CAPS_MAKE ("S420") ";" \ + GST_VIDEO_CAPS_MAKE ("I420") ";" \ + GST_VIDEO_CAPS_MAKE ("SYVY") ";" \ + GST_VIDEO_CAPS_MAKE ("UYVY") ";" \ + GST_VIDEO_CAPS_MAKE ("SUYV") ";" \ + GST_VIDEO_CAPS_MAKE ("YUYV") ";" \ + GST_VIDEO_CAPS_MAKE ("SUY2") ";" \ + GST_VIDEO_CAPS_MAKE ("YUY2") ";" \ + GST_VIDEO_CAPS_MAKE ("ITLV")) + ); + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS(GST_VIDEO_CAPS_MAKE("BGRx") ";" \ + GST_VIDEO_CAPS_MAKE ("ST12") ";" \ + GST_VIDEO_CAPS_MAKE ("SN12") ";" \ + GST_VIDEO_CAPS_MAKE ("NV12") ";" \ + GST_VIDEO_CAPS_MAKE ("S420") ";" \ + GST_VIDEO_CAPS_MAKE ("I420") ";" \ + GST_VIDEO_CAPS_MAKE ("SYVY") ";" \ + GST_VIDEO_CAPS_MAKE ("UYVY") ";" \ + GST_VIDEO_CAPS_MAKE ("SUYV") ";" \ + GST_VIDEO_CAPS_MAKE ("YUYV") ";" \ + GST_VIDEO_CAPS_MAKE ("SUY2") ";" \ + GST_VIDEO_CAPS_MAKE ("YUY2")) + ); + +static void gst_fimcconvert_base_init(gpointer g_class); +static void gst_fimcconvert_class_init(GstFimcConvertClass * klass); +static void gst_fimcconvert_init(GstFimcConvert * fimcconvert); +static void gst_fimcconvert_finalize(GstFimcConvert * fimcconvert); +static GstStateChangeReturn gst_fimcconvert_change_state (GstElement *element, GstStateChange transition); +static GstCaps * gst_fimcconvert_transform_caps(GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, GstCaps *filter); +static GstCaps* gst_fimcconvert_fixate_caps(GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, GstCaps *othercaps); +static gboolean gst_fimcconvert_set_caps(GstBaseTransform *trans, GstCaps *in, GstCaps *out); +static gboolean gst_fimcconvert_start(GstBaseTransform *trans); +static gboolean gst_fimcconvert_stop(GstBaseTransform *trans); +static gboolean gst_fimcconvert_get_unit_size(GstBaseTransform *trans, GstCaps *caps, guint *size); +static GstFlowReturn gst_fimcconvert_transform(GstBaseTransform *trans, GstBuffer *in, GstBuffer *out); +static void gst_fimcconvert_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gst_fimcconvert_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); +static GstFlowReturn gst_fimcconvert_prepare_output_buffer(GstBaseTransform *trans, GstBuffer *input, GstBuffer **buf); +static gboolean gst_fimcconvert_priv_init (GstFimcConvert *fimcconvert); +static void gst_fimcconvert_reset (GstFimcConvert *fimcconvert); +static gboolean gst_fimcconvert_tbm_create_and_map_bo(GstFimcConvert *fimcconvert, FimcConvertGemCreateType type); +static void gst_fimcconvert_tbm_unmap_and_destroy_bo(GstFimcConvert *fimcconvert, FimcConvertGemCreateType type, int index); +static void gst_fimcconvert_buffer_finalize(GstFimcConvertBuffer *buffer); +static gboolean gst_fimcconvert_drm_ipp_init(GstFimcConvert *fimcconvert); +static gboolean gst_fimcconvert_drm_ipp_ctrl(GstFimcConvert *fimcconvert, FimcConvertIppCtrl cmd); +static void gst_fimcconvert_drm_ipp_fini(GstFimcConvert *fimcconvert); + +static GstElementClass *parent_class = NULL; + +/* for fimc multi instance */ +GMutex * instance_lock = NULL; +guint instance_lock_count; + +#define MAX_IPP_EVENT_BUFFER_SIZE 1024 +#define FIMCCONVERT_TYPE_ROTATE (fimcconvert_rotate_get_type()) +#define FIMCCONVERT_TYPE_FLIP (fimcconvert_flip_get_type()) + +static GType +fimcconvert_rotate_get_type (void) +{ + static GType fimcconvert_rotate_type = 0; + GST_LOG ("[%d : %s] ENTERING",__LINE__,__func__); + + if (!fimcconvert_rotate_type) { + static GEnumValue fimcconvert_rotate_types[] = { + {FIMCCONVERT_ROTATE_NONE, "0", "No Rotation"}, + {FIMCCONVERT_ROTATE_90, "90", "Rotate 90 degrees"}, + {FIMCCONVERT_ROTATE_180, "180", "Rotate 180 degrees"}, + {FIMCCONVERT_ROTATE_270, "270", "Rotate 270 degrees"}, + {0, NULL, NULL}, + }; + fimcconvert_rotate_type = g_enum_register_static ("FIMCConvertRotateType", fimcconvert_rotate_types); + } + + GST_LOG ("[%d : %s] LEAVING",__LINE__,__func__); + return fimcconvert_rotate_type; +} + +static GType +fimcconvert_flip_get_type (void) +{ + static GType fimcconvert_flip_type = 0; + GST_LOG ("[%d : %s] ENTERING",__LINE__,__func__); + + if (!fimcconvert_flip_type) { + static GEnumValue fimcconvert_flip_types[] = { + {FIMCCONVERT_FLIP_NONE,"NONE","No Flip"}, + {FIMCCONVERT_FLIP_VERTICAL,"VERTICAL","Vertical Flip"}, + {FIMCCONVERT_FLIP_HORIZONTAL,"HORIZONTAL","Horizontal Flip"}, + {0, NULL, NULL}, + }; + fimcconvert_flip_type = g_enum_register_static ("FIMCConvertFlipType", fimcconvert_flip_types); + } + + GST_LOG ("[%d : %s] LEAVING",__LINE__,__func__); + return fimcconvert_flip_type; +} + +GType +gst_fimcconvert_get_type(void) +{ + static GType fimcconvert_type = 0; + + if (!fimcconvert_type) { + static const GTypeInfo fimcconvert_info = { + sizeof(GstFimcConvertClass), + gst_fimcconvert_base_init, + NULL, + (GClassInitFunc) gst_fimcconvert_class_init, + NULL, + NULL, + sizeof(GstFimcConvert), + 0, + (GInstanceInitFunc) gst_fimcconvert_init, + }; + + fimcconvert_type = g_type_register_static(GST_TYPE_BASE_TRANSFORM, "GstFimcConvert", &fimcconvert_info, 0); + } + return fimcconvert_type; +} + +static GstFimcConvertBuffer * +gst_fimcconvert_buffer_new(GstFimcConvert *fimcconvert, guint buf_size) +{ + GstFimcConvertBuffer *buffer = NULL; + + buffer = (GstFimcConvertBuffer *)malloc(sizeof(*buffer)); + + GST_LOG_OBJECT(fimcconvert, "creating fimcconvert buffer(%p)", buffer); + + buffer->actual_size = buf_size; + buffer->buffer = gst_buffer_new(); + buffer->fimcconvert = gst_object_ref(GST_OBJECT(fimcconvert)); + + return buffer; +} + +static void +gst_fimcconvert_buffer_finalize(GstFimcConvertBuffer *buffer) +{ + GstFimcConvert *fimcconvert = NULL; + SCMN_IMGB *imgb = NULL; +#ifdef USE_DETECT_JPEG + GstMemory *imgb_memory = NULL; + GstMapInfo imgb_info = GST_MAP_INFO_INIT; +#endif + + fimcconvert = buffer->fimcconvert; + + GST_DEBUG_OBJECT (fimcconvert, "[START]"); + +#ifdef DEBUG_FOR_DV + if (total_converted_frame_count > 0) { + if (++total_buffer_unref_count <= 10) { + GST_WARNING_OBJECT (fimcconvert, "%2dth of buffer(%p) unrefering", total_buffer_unref_count, buffer); + } + } +#endif + + g_mutex_lock (fimcconvert->buf_idx_lock); + if (fimcconvert->dst_buf_num > 0) { + fimcconvert->dst_buf_num--; + GST_LOG_OBJECT(fimcconvert, "unrefering a buffer(%p), now number of pending buffers(%d)", buffer, fimcconvert->dst_buf_num); + } else { + if (fimcconvert->is_drm_inited) { + GST_WARNING_OBJECT(fimcconvert, "something wrong..trying to unrefer a buffer(%p)", buffer); + } + } + +#ifdef USE_DETECT_JPEG + /* free memory for JPEG data */ + if (gst_buffer_n_memory(buffer->buffer) > 2) { + imgb_memory = gst_buffer_peek_memory(buffer->buffer, 1); + gst_memory_map(imgb_memory, &imgb_info, GST_MAP_READ); + imgb = (SCMN_IMGB *)imgb_info.data; + gst_memory_unmap(imgb_memory, &imgb_info); + if (imgb->jpeg_data) { + GST_INFO_OBJECT(fimcconvert, "JPEG data(%p) is detected, free it", imgb->jpeg_data); + free(imgb->jpeg_data); + } + } +#endif + + gst_object_unref(fimcconvert); + free(buffer); + + g_mutex_unlock (fimcconvert->buf_idx_lock); + + GST_DEBUG_OBJECT (fimcconvert, "[END]"); +} + +static gboolean +gst_fimcconvert_is_buffer_available (GstFimcConvert *fimcconvert) +{ + g_return_val_if_fail (GST_IS_FIMCCONVERT (fimcconvert), FALSE); + + g_mutex_lock (fimcconvert->buf_idx_lock); + if (fimcconvert->dst_buf_num < fimcconvert->num_of_dst_buffers) { + fimcconvert->dst_buf_num++; + } else { + int timeout_count = 50; + g_mutex_unlock (fimcconvert->buf_idx_lock); + /* waiting for unref buffer */ + while (fimcconvert->dst_buf_num == fimcconvert->num_of_dst_buffers) { + if (timeout_count == 0) { + GST_ERROR_OBJECT (fimcconvert, "timeout.."); + return FALSE; + } + GST_WARNING_OBJECT (fimcconvert, "wait until downstream plugin unrefers a buffer"); + g_usleep (G_USEC_PER_SEC / 10); + timeout_count--; + } + g_mutex_lock (fimcconvert->buf_idx_lock); + fimcconvert->dst_buf_num++; + } + GST_LOG_OBJECT (fimcconvert, "Number of dst buffers(%d), refered number of buffers(%d)", fimcconvert->num_of_dst_buffers, fimcconvert->dst_buf_num); + g_mutex_unlock (fimcconvert->buf_idx_lock); + + return TRUE; +} + +static gboolean +gst_fimcconvert_drm_ipp_init(GstFimcConvert *fimcconvert) +{ + Display *dpy = NULL; + int i = 0; + int j = 0; + int ret = 0; + int eventBase = 0; + int errorBase = 0; + int dri2Major = 0; + int dri2Minor = 0; + char *driverName = NULL; + char *deviceName = NULL; + struct drm_auth auth_arg = {0}; + struct drm_exynos_ipp_property property; + struct drm_exynos_sz src_sz; + struct drm_exynos_sz dst_sz; + enum drm_exynos_degree dst_degree = EXYNOS_DRM_DEGREE_0; + enum drm_exynos_flip dst_flip = EXYNOS_DRM_FLIP_NONE; + + if (fimcconvert->drm_fimc_fd != -1) { + /* maybe skipping convert case */ + GST_WARNING_OBJECT (fimcconvert, "already initialized drm_fd (%d)", fimcconvert->drm_fimc_fd); + return TRUE; + } + + g_return_val_if_fail (GST_IS_FIMCCONVERT (fimcconvert), FALSE); + + if (fimcconvert->drm_tbm_fd != -1) { + fimcconvert->drm_fimc_fd = fimcconvert->drm_tbm_fd; + GST_WARNING_OBJECT (fimcconvert, "use drm fd(%d) for IPP", fimcconvert->drm_fimc_fd); + } else { + + dpy = XOpenDisplay(0); + if (!dpy) { + GST_ERROR_OBJECT(fimcconvert, "failed to XOpenDisplay()"); + goto ERROR_CASE; + } + + /* DRI2 */ + if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) { + GST_ERROR_OBJECT(fimcconvert, "failed to DRI2QueryExtension()"); + goto ERROR_CASE; + } + + if (!DRI2QueryVersion(dpy, &dri2Major, &dri2Minor)) { + GST_ERROR_OBJECT(fimcconvert, "failed to DRI2QueryVersion"); + goto ERROR_CASE; + } + + if (!DRI2Connect(dpy, RootWindow(dpy, DefaultScreen(dpy)), &driverName, &deviceName)) { + GST_ERROR_OBJECT(fimcconvert,"failed to DRI2Connect"); + goto ERROR_CASE; + } + + /* get the drm_fd though opening the deviceName */ + fimcconvert->drm_fimc_fd = open(deviceName, O_RDWR); + if (fimcconvert->drm_fimc_fd < 0) { + GST_ERROR_OBJECT(fimcconvert,"cannot open drm device (%s)", deviceName); + goto ERROR_CASE; + } + GST_INFO("Open drm device : %s, fd(%d)", deviceName, fimcconvert->drm_fimc_fd); + + /* get magic from drm to authentication */ + if (ioctl(fimcconvert->drm_fimc_fd, DRM_IOCTL_GET_MAGIC, &auth_arg)) { + GST_ERROR_OBJECT(fimcconvert,"cannot get drm auth magic"); + close(fimcconvert->drm_fimc_fd); + fimcconvert->drm_fimc_fd = -1; + goto ERROR_CASE; + } + + if (!DRI2Authenticate(dpy, RootWindow(dpy, DefaultScreen(dpy)), auth_arg.magic)) { + GST_ERROR_OBJECT(fimcconvert,"cannot get drm authentication from X"); + close(fimcconvert->drm_fimc_fd); + fimcconvert->drm_fimc_fd = -1; + goto ERROR_CASE; + } + + fimcconvert->drm_tbm_fd = fimcconvert->drm_fimc_fd; + } + + fimcconvert->tbm = tbm_bufmgr_init (fimcconvert->drm_tbm_fd); + if (!fimcconvert->tbm) { + GST_ERROR_OBJECT (fimcconvert, "failed to initialize tizen buffer manager "); + goto ERROR_CASE; + } else { + GST_INFO_OBJECT (fimcconvert, "tbm bufmgr(%x) initialized : using drm fd(%d)", fimcconvert->tbm, fimcconvert->drm_tbm_fd); + } + + for (i=0; igem_info_src[i][j], 0x0, sizeof(GemInfoSrc)); + } + } + for (i=0; igem_info_src_normal_fmt[i], 0x0, sizeof(GemInfoDst)); + } + for (i=0; igem_info_dst[i][j], 0x0, sizeof(GemInfoDst)); + } + } + fimcconvert->ipp_prop_id = 0; + + /* Update src/dst size */ + src_sz.hsize = fimcconvert->src_caps_width; + src_sz.vsize = fimcconvert->src_caps_height; + dst_sz.hsize = fimcconvert->dst_caps_width; + dst_sz.vsize = fimcconvert->dst_caps_height; + + /* Update rotation information */ + switch (fimcconvert->rotate_ang) { + case 90: + dst_degree = EXYNOS_DRM_DEGREE_90; + break; + case 270: + dst_degree = EXYNOS_DRM_DEGREE_270; + break; + case 0: + dst_degree = EXYNOS_DRM_DEGREE_0; + break; + case 180: + dst_degree = EXYNOS_DRM_DEGREE_180; + break; + default: + break; + } + GST_INFO_OBJECT (fimcconvert, "set rotate angle to %d", dst_degree); + + /* Update flip information */ + switch (fimcconvert->dst_flip) { + case 0: + dst_flip = EXYNOS_DRM_FLIP_NONE; + break; + case 1: + dst_flip = EXYNOS_DRM_FLIP_VERTICAL; + break; + case 2: + dst_flip = EXYNOS_DRM_FLIP_HORIZONTAL; + break; + default: + break; + } + GST_INFO_OBJECT (fimcconvert, "set flip to %d", dst_flip); + + /* Set DRM property, IPP_CMD_M2M */ + ret = exynos_drm_ipp_set_property(fimcconvert->drm_fimc_fd, &property, &src_sz, &dst_sz, fimcconvert->src_format_drm, fimcconvert->dst_format_drm, IPP_CMD_M2M, dst_degree, dst_flip); + if (ret) { + GST_ERROR_OBJECT (fimcconvert, "failed to set ipp property"); + gst_fimcconvert_drm_ipp_fini (fimcconvert); + goto ERROR_CASE; + } else { + fimcconvert->ipp_prop_id = property.prop_id; + GST_INFO_OBJECT (fimcconvert, "set IPP_CMD_M2M, ipp_prop_id(%d)", fimcconvert->ipp_prop_id); + } +#if 0 + /* Start */ + if (!gst_fimcconvert_drm_ipp_ctrl(fimcconvert, FIMCCONVERT_IPP_CTRL_START)) { + GST_ERROR_OBJECT (fimcconvert, "failed to gst_fimcconvert_drm_ipp_ctrl(START)"); + } +#endif + fimcconvert->is_drm_inited = FALSE; + + if (dpy) { + XCloseDisplay(dpy); + } + if (driverName) { + free(driverName); + } + if (deviceName) { + free(deviceName); + } + + return TRUE; + +ERROR_CASE: + if (dpy) { + XCloseDisplay(dpy); + } + if (driverName) { + free(driverName); + } + if (deviceName) { + free(deviceName); + } + + return FALSE; +} + +static gboolean +gst_fimcconvert_drm_ipp_ctrl(GstFimcConvert *fimcconvert, FimcConvertIppCtrl cmd) +{ + int ret = 0; + enum drm_exynos_ipp_ctrl ctrl_cmd; + + g_return_val_if_fail (GST_IS_FIMCCONVERT (fimcconvert), FALSE); + + if (fimcconvert->drm_fimc_fd < 0) { + GST_ERROR_OBJECT(fimcconvert, "already closed drm_fimc_fd(%d)", fimcconvert->drm_fimc_fd); + return FALSE; + } + if (fimcconvert->ipp_prop_id == 0) { + GST_ERROR_OBJECT(fimcconvert, "ipp_prop_id is 0.."); + return FALSE; + } + + switch(cmd) { + case FIMCCONVERT_IPP_CTRL_STOP: + ctrl_cmd = IPP_CTRL_STOP; + break; + case FIMCCONVERT_IPP_CTRL_START: + ctrl_cmd = IPP_CTRL_PLAY; + break; + default: + GST_ERROR_OBJECT(fimcconvert, "cmd is not valid(%d)", cmd); + return FALSE; + } + + ret = exynos_drm_ipp_cmd_ctrl(fimcconvert->drm_fimc_fd, fimcconvert->ipp_prop_id, ctrl_cmd); + if (ret) { + GST_ERROR_OBJECT (fimcconvert, "failed to stop ipp ctrl IPP_CMD_M2M"); + return FALSE; + } + + return TRUE; +} + +static void +gst_fimcconvert_drm_ipp_fini(GstFimcConvert *fimcconvert) +{ + int i = 0; + int ret = 0; + + g_return_if_fail (GST_IS_FIMCCONVERT (fimcconvert)); + + if (fimcconvert->drm_fimc_fd < 0) { + GST_WARNING_OBJECT(fimcconvert, "already closed drm_fimc_fd(%d)", fimcconvert->drm_fimc_fd); + return; + + } else if (fimcconvert->drm_fimc_fd >= 0) { + if (fimcconvert->is_drm_inited) { + /* For source buffer dequeue to IPP */ + for (i = 0; i < MAX_SRC_BUF_NUM; i++) { + if (fimcconvert->gem_info_src[i][SCMN_Y_PLANE].gem_handle) { + ret = exynos_drm_ipp_queue_buf(fimcconvert->drm_fimc_fd, EXYNOS_DRM_OPS_SRC, IPP_BUF_DEQUEUE, fimcconvert->ipp_prop_id, i, + fimcconvert->gem_info_src[i][SCMN_Y_PLANE].gem_handle, fimcconvert->gem_info_src[i][SCMN_CB_PLANE].gem_handle, fimcconvert->gem_info_src[i][SCMN_CR_PLANE].gem_handle); + if (ret < 0) { + GST_ERROR_OBJECT (fimcconvert, "src buffer map to IPP failed, src_buf_idx(%d)", i); + } + } + } + /* For destination buffer dequeue to IPP */ + for (i = 0; i < fimcconvert->num_of_dst_buffers; i++) { + if (fimcconvert->gem_info_dst[i][SCMN_Y_PLANE].gem_handle) { + ret = exynos_drm_ipp_queue_buf(fimcconvert->drm_fimc_fd, EXYNOS_DRM_OPS_DST, IPP_BUF_DEQUEUE, fimcconvert->ipp_prop_id, i, + fimcconvert->gem_info_dst[i][SCMN_Y_PLANE].gem_handle, fimcconvert->gem_info_dst[i][SCMN_CB_PLANE].gem_handle, fimcconvert->gem_info_dst[i][SCMN_CR_PLANE].gem_handle); + if (ret < 0) { + GST_ERROR_OBJECT (fimcconvert, "dst buffer map to IPP failed, dst_buf_idx(%d)", i); + } + } + } + /* Set IPP to stop */ + if (!gst_fimcconvert_drm_ipp_ctrl(fimcconvert, FIMCCONVERT_IPP_CTRL_STOP)) { + GST_ERROR_OBJECT (fimcconvert, "failed to gst_fimcconvert_drm_ipp_ctrl(STOP)"); + } + /* Memory unmap & close gem */ + /* dst buffer */ + for (i = 0; i < fimcconvert->num_of_dst_buffers; i++) { + gst_fimcconvert_tbm_unmap_and_destroy_bo (fimcconvert, FIMCCONVERT_GEM_FOR_DST, i); + } + /* src buffer */ + for (i = 0; i < MAX_SRC_BUF_NUM; i++) { + gst_fimcconvert_tbm_unmap_and_destroy_bo (fimcconvert, FIMCCONVERT_GEM_FOR_SRC, i); + } + } + + /* Deinitialize TBM */ + if (fimcconvert->tbm) { + tbm_bufmgr_deinit(fimcconvert->tbm); + } + + /* Close DRM */ + if (fimcconvert->drm_tbm_fd != fimcconvert->drm_fimc_fd) { + GST_INFO_OBJECT (fimcconvert, "close drm_fimc_fd(%d)", fimcconvert->drm_fimc_fd); + close(fimcconvert->drm_fimc_fd); + } + + fimcconvert->drm_fimc_fd = -1; + fimcconvert->ipp_prop_id = 0; + fimcconvert->tbm = 0; + fimcconvert->drm_tbm_fd = -1; + fimcconvert->is_drm_inited = FALSE; + + return; + } +} + +static void +gst_fimcconvert_base_init(gpointer g_class) +{ +} + +static void +gst_fimcconvert_class_init(GstFimcConvertClass *klass) +{ + GObjectClass *gobject_class; + GstBaseTransformClass *trans_class; + GstElementClass *gstelement_class = GST_ELEMENT_CLASS(klass); + + gobject_class =(GObjectClass *) klass; + trans_class =(GstBaseTransformClass *) klass; + + gobject_class->finalize =(GObjectFinalizeFunc) gst_fimcconvert_finalize; + gobject_class->set_property = gst_fimcconvert_set_property; + gobject_class->get_property = gst_fimcconvert_get_property; + + gstelement_class->change_state = GST_DEBUG_FUNCPTR(gst_fimcconvert_change_state); + gst_element_class_set_static_metadata(gstelement_class, + "Video Scale, Rotate, Colorspace Convert Plug-in based on FIMC", + "Filter/Effect/Video", + "Video scale, rotate and colorspace convert using FIMC", + "Samsung Electronics Co"); + gst_element_class_add_pad_template(gstelement_class, gst_static_pad_template_get(&src_template)); + gst_element_class_add_pad_template(gstelement_class, gst_static_pad_template_get(&sink_template)); + + trans_class->transform_caps = GST_DEBUG_FUNCPTR(gst_fimcconvert_transform_caps); + trans_class->fixate_caps = GST_DEBUG_FUNCPTR(gst_fimcconvert_fixate_caps); + trans_class->set_caps = GST_DEBUG_FUNCPTR(gst_fimcconvert_set_caps); + trans_class->start = GST_DEBUG_FUNCPTR(gst_fimcconvert_start); + trans_class->stop = GST_DEBUG_FUNCPTR(gst_fimcconvert_stop); + trans_class->get_unit_size = GST_DEBUG_FUNCPTR(gst_fimcconvert_get_unit_size); + + trans_class->transform = GST_DEBUG_FUNCPTR(gst_fimcconvert_transform); + trans_class->prepare_output_buffer = GST_DEBUG_FUNCPTR(gst_fimcconvert_prepare_output_buffer); + + trans_class->passthrough_on_same_caps = TRUE; + + parent_class = g_type_class_peek_parent(klass); + + GST_DEBUG_CATEGORY_INIT(fimcconvert_debug, "fimcconvert", 0, "fimcconvert element"); + + g_object_class_install_property (gobject_class, PROP_ROT_ANG, + g_param_spec_enum ("rotate", "Rotate", "Rotate can be 0, 90, 180 or 270", + FIMCCONVERT_TYPE_ROTATE, FIMCCONVERT_ROTATE_NONE, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_DST_WIDTH, + g_param_spec_int ("dst-width", "Output video width", "Output video width. If setting 0, output video width will be media src's width", + FIMCCONVERT_DST_WIDTH_MIN, FIMCCONVERT_DST_WIDTH_MAX, FIMCCONVERT_DST_WIDTH_DEFAULT, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_DST_HEIGHT, + g_param_spec_int ("dst-height", "Output video height", "Output video height. If setting 0, output video height will be media src's height", + FIMCCONVERT_DST_HEIGHT_MIN, FIMCCONVERT_DST_HEIGHT_MAX, FIMCCONVERT_DST_HEIGHT_DEFAULT, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_FLIP, + g_param_spec_enum ("flip", "Flip", "Flip can be 0, 1, 2", + FIMCCONVERT_TYPE_FLIP, FIMCCONVERT_FLIP_NONE, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_SRC_RANDOM_IDX, + g_param_spec_boolean ("src-rand-idx", "Random src buffer index", "Random src buffer index. If setting TRUE, fimcconvert does not manage index of src buffer from upstream src-plugin", + TRUE, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_DST_BUFFER_NUM, + g_param_spec_int ("dst-buffer-num", "Number of dst buffers", "Number of destination buffers", + FIMCCONVERT_DST_BUFFER_MIN, FIMCCONVERT_DST_BUFFER_MAX, FIMCCONVERT_DST_BUFFER_DEFAULT, G_PARAM_READWRITE)); +} + +static void +gst_fimcconvert_init(GstFimcConvert * fimcconvert) +{ + GST_DEBUG_OBJECT (fimcconvert, "[START]"); + gst_base_transform_set_qos_enabled(GST_BASE_TRANSFORM(fimcconvert), TRUE); + + /* pad setting */ + fimcconvert->src_pad = GST_BASE_TRANSFORM_SRC_PAD(fimcconvert); + + /* private values init */ + gst_fimcconvert_priv_init (fimcconvert); + + /* property values init */ + fimcconvert->is_random_src_idx = TRUE; + fimcconvert->num_of_dst_buffers = FIMCCONVERT_DST_BUFFER_DEFAULT; + fimcconvert->rotate_ang = FIMCCONVERT_ROTATE_NONE; + fimcconvert->dst_flip = FIMCCONVERT_FLIP_NONE; + + if(!instance_lock) { + instance_lock = g_mutex_new(); + } + g_mutex_lock (instance_lock); + instance_lock_count++; + g_mutex_unlock (instance_lock); + + fimcconvert->fd_lock = g_mutex_new (); + if (!fimcconvert->fd_lock) { + GST_ERROR ("Failed to created mutex..."); + } + fimcconvert->buf_idx_lock = g_mutex_new (); + if (!fimcconvert->buf_idx_lock) { + GST_ERROR ("Failed to created mutex..."); + } + + +#ifdef DEBUG_FOR_DV + GST_WARNING_OBJECT (fimcconvert, "[END]"); +#else + GST_DEBUG_OBJECT (fimcconvert, "[END]"); +#endif +} + +static gboolean +gst_fimcconvert_priv_init (GstFimcConvert *fimcconvert) +{ + g_return_val_if_fail (GST_IS_FIMCCONVERT (fimcconvert), FALSE); + + fimcconvert->drm_fimc_fd = -1; + fimcconvert->drm_tbm_fd = -1; + + fimcconvert->src_buf_idx = 0; + fimcconvert->dst_buf_idx = 0; + + fimcconvert->is_first_set_for_src = TRUE; + fimcconvert->is_first_set_for_dst = TRUE; + + fimcconvert->buf_share_method_type = 0; + + fimcconvert->is_src_format_std = FALSE; + fimcconvert->is_same_caps = FALSE; + fimcconvert->do_skip = FALSE; + + fimcconvert->jpeg_data = NULL; + fimcconvert->jpeg_data_size = 0; + + return TRUE; +} + +static void +gst_fimcconvert_finalize(GstFimcConvert *fimcconvert) +{ + g_return_if_fail (GST_IS_FIMCCONVERT (fimcconvert)); + GST_DEBUG_OBJECT (fimcconvert, "[START]"); + + if (fimcconvert->is_drm_inited) { + gst_fimcconvert_reset(fimcconvert); + } + + if (fimcconvert->fd_lock) { + g_mutex_free (fimcconvert->fd_lock); + fimcconvert->fd_lock = NULL; + } + if (fimcconvert->buf_idx_lock) { + g_mutex_free (fimcconvert->buf_idx_lock); + fimcconvert->buf_idx_lock = NULL; + } + + g_mutex_lock (instance_lock); + instance_lock_count--; + g_mutex_unlock (instance_lock); + if (instance_lock_count == 0) { + g_mutex_free (instance_lock); + instance_lock = NULL; + } + +#ifdef DEBUG_FOR_DV + GST_WARNING_OBJECT (fimcconvert, "[END] total number of converted frames : %d",total_converted_frame_count); + GST_WARNING_OBJECT (fimcconvert, "[END] total number of unrefered buffers : %d",total_buffer_unref_count); + total_converted_frame_count = 0; + total_buffer_unref_count = 0; +#else + GST_DEBUG_OBJECT (fimcconvert, "[END]"); +#endif + + G_OBJECT_CLASS(parent_class)->finalize(G_OBJECT(fimcconvert)); + +} + +static void +gst_fimcconvert_reset (GstFimcConvert *fimcconvert) +{ + g_return_if_fail (GST_IS_FIMCCONVERT (fimcconvert)); + + GST_DEBUG_OBJECT (fimcconvert, "[START]"); + + g_mutex_lock (fimcconvert->fd_lock); + g_mutex_lock (instance_lock); + + if (fimcconvert->drm_fimc_fd >= 0) { + FIMCCONVERT_SEND_CUSTOM_EVENT_TO_SINK_WITH_DATA( 0 ); + gst_fimcconvert_drm_ipp_fini(fimcconvert); + gst_fimcconvert_priv_init (fimcconvert); + } + + g_mutex_unlock (instance_lock); + g_mutex_unlock (fimcconvert->fd_lock); + + GST_DEBUG_OBJECT (fimcconvert, "[END]"); + + return; +} + +static GstStateChangeReturn +gst_fimcconvert_change_state (GstElement *element, GstStateChange transition) +{ + GstFimcConvert *fimcconvert = NULL; + GstStateChangeReturn stateret = GST_STATE_CHANGE_SUCCESS; + + fimcconvert = GST_FIMCCONVERT(element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + GST_INFO_OBJECT( fimcconvert, "GST_STATE_CHANGE_NULL_TO_READY"); + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + GST_INFO_OBJECT( fimcconvert, "GST_STATE_CHANGE_READY_TO_PAUSED"); + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + GST_INFO_OBJECT( fimcconvert, "GST_STATE_CHANGE_PAUSED_TO_PLAYING"); + break; + default: + break; + } + stateret = parent_class->change_state (element, transition); + if ( stateret != GST_STATE_CHANGE_SUCCESS ) { + GST_ERROR_OBJECT( fimcconvert, "chane state error in parent class"); + return GST_STATE_CHANGE_FAILURE; + } + + switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + GST_INFO_OBJECT( fimcconvert, "GST_STATE_CHANGE_PLAYING_TO_PAUSED"); + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + GST_INFO_OBJECT( fimcconvert, "GST_STATE_CHANGE_PAUSED_TO_READY"); + break; + case GST_STATE_CHANGE_READY_TO_NULL: + GST_INFO_OBJECT( fimcconvert, "GST_STATE_CHANGE_READY_TO_NULL"); + gst_fimcconvert_reset(fimcconvert); + break; + default: + break; + } + + return stateret; +} + +static void +gst_fimcconvert_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstFimcConvert *fimcconvert = GST_FIMCCONVERT (object); + guint rotate_ang; + gint width; + gint height; + gint flip; + gboolean is_rand_src_idx; + guint dst_buffer_num; + + switch (prop_id) { + case PROP_ROT_ANG: + rotate_ang = g_value_get_enum(value); + if(rotate_ang != fimcconvert->rotate_ang) { + fimcconvert->rotate_ang = rotate_ang; + GST_INFO_OBJECT (fimcconvert, "Rotate angle value = %d", rotate_ang); + gst_fimcconvert_reset(fimcconvert); + } + break; + + case PROP_DST_WIDTH: + width = g_value_get_int(value); + if (width != fimcconvert->dst_width) { + if (!width) { + fimcconvert->dst_width = fimcconvert->src_caps_width; + } else { + fimcconvert->dst_width = width; + } + GST_INFO_OBJECT (fimcconvert, "Going to set output width = %d", fimcconvert->dst_width); + fimcconvert->dst_caps_width = fimcconvert->dst_width; + gst_fimcconvert_reset(fimcconvert); + } else { + GST_WARNING_OBJECT (fimcconvert, "skip set width.. width(%d),fimcconvert->dst_width(%d)",width,fimcconvert->dst_width); + } + break; + + case PROP_DST_HEIGHT: + height = g_value_get_int(value); + if (height != fimcconvert->dst_height) { + if (!height) { + fimcconvert->dst_height = fimcconvert->src_caps_height; + } else { + fimcconvert->dst_height = height; + } + GST_INFO_OBJECT (fimcconvert, "Going to set output height = %d", fimcconvert->dst_height); + fimcconvert->dst_caps_height = fimcconvert->dst_height; + gst_fimcconvert_reset(fimcconvert); + } else { + GST_WARNING_OBJECT (fimcconvert, "skip set height.. height(%d),fimcconvert->dst_height(%d)",height,fimcconvert->dst_height); + } + break; + + case PROP_FLIP: + flip = g_value_get_enum(value); + if (flip != fimcconvert->dst_flip) { + fimcconvert->dst_flip = flip; + GST_INFO_OBJECT (fimcconvert, "Going to set flip = %d", fimcconvert->dst_flip); + gst_fimcconvert_reset(fimcconvert); + } + break; + + case PROP_SRC_RANDOM_IDX: + is_rand_src_idx = g_value_get_boolean(value); + if (fimcconvert->is_random_src_idx != is_rand_src_idx) { + fimcconvert->is_random_src_idx = is_rand_src_idx; + GST_INFO_OBJECT (fimcconvert, "src index ordering from upstream src plugin is random? %d", fimcconvert->is_random_src_idx); + gst_fimcconvert_reset(fimcconvert); + } + break; + + case PROP_DST_BUFFER_NUM: + dst_buffer_num = (guint)g_value_get_int(value); + if (fimcconvert->num_of_dst_buffers != dst_buffer_num) { + fimcconvert->num_of_dst_buffers = dst_buffer_num; + GST_INFO_OBJECT (fimcconvert, "Number of dst buffers = %d", dst_buffer_num); + gst_fimcconvert_reset(fimcconvert); + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_fimcconvert_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstFimcConvert *fimcconvert = GST_FIMCCONVERT (object); + + switch (prop_id) { + case PROP_ROT_ANG: + g_value_set_enum(value, fimcconvert->rotate_ang); + break; + case PROP_DST_WIDTH: + g_value_set_int(value, fimcconvert->dst_width); + break; + case PROP_DST_HEIGHT: + g_value_set_int(value, fimcconvert->dst_height); + break; + case PROP_FLIP: + g_value_set_enum(value, fimcconvert->dst_flip); + break; + case PROP_SRC_RANDOM_IDX: + g_value_set_boolean(value, fimcconvert->is_random_src_idx); + break; + case PROP_DST_BUFFER_NUM: + g_value_set_int(value, (int)fimcconvert->num_of_dst_buffers); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_fimcconvert_start(GstBaseTransform *trans) +{ + /* Not doing anything here */ + return TRUE; +} + +static gboolean +gst_fimcconvert_stop(GstBaseTransform *trans) +{ + /* Not doing anything here */ + return TRUE; +} + +static gboolean +gst_fimcconvert_set_imgb_info_for_dst(GstFimcConvert *fimcconvert, GstBuffer *buf) +{ + SCMN_IMGB *imgb = NULL; + guint idx = 0; + + g_return_val_if_fail (GST_IS_FIMCCONVERT (fimcconvert), FALSE); + g_return_val_if_fail (buf, FALSE); + + idx = fimcconvert->dst_buf_idx; + + g_return_val_if_fail (fimcconvert->gem_info_dst[idx][SCMN_Y_PLANE].gem_handle, FALSE); + g_return_val_if_fail (fimcconvert->gem_info_dst[idx][SCMN_Y_PLANE].usr_addr, FALSE); + + imgb = (SCMN_IMGB *)malloc(sizeof(SCMN_IMGB)); + if (imgb == NULL) { + GST_ERROR_OBJECT (fimcconvert, "SCMN_IMGB memory allocation failed"); + return FALSE; + } + memset(imgb, 0x0, sizeof(SCMN_IMGB)); + + GST_INFO_OBJECT (fimcconvert, "OutBuf :: buf_share_method_type (%d)", fimcconvert->buf_share_method_type); + + if (fimcconvert->buf_share_method_type == BUF_SHARE_METHOD_PADDR) { + + if (!fimcconvert->gem_info_dst[idx][SCMN_Y_PLANE].phy_addr) { + free(imgb); + GST_ERROR_OBJECT (fimcconvert, "OutBuf :: phy_addr is null"); + return FALSE; + } + + imgb->p[SCMN_Y_PLANE] = (void*)(unsigned long)fimcconvert->gem_info_dst[idx][SCMN_Y_PLANE].phy_addr; + imgb->a[SCMN_Y_PLANE] = (void*)(unsigned long)fimcconvert->gem_info_dst[idx][SCMN_Y_PLANE].usr_addr; + imgb->w[SCMN_Y_PLANE] = fimcconvert->dst_caps_width; + imgb->h[SCMN_Y_PLANE] = fimcconvert->dst_caps_height; + imgb->s[SCMN_Y_PLANE] = imgb->w[SCMN_Y_PLANE]; + imgb->e[SCMN_Y_PLANE] = imgb->h[SCMN_Y_PLANE]; + imgb->buf_share_method = BUF_SHARE_METHOD_PADDR; + + if (fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','T','1','2') + || fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','N','1','2')) { + if (fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','N','1','2')) { + GST_INFO_OBJECT (fimcconvert, "OutBuf :: It's SN12"); + imgb->cs = SCMN_CS_NV12; + } else { + GST_INFO_OBJECT (fimcconvert, "OutBuf :: It's ST12"); + imgb->cs = SCMN_CS_NV12_T64X32; + } + imgb->p[SCMN_CB_PLANE] = (void*)(unsigned long)fimcconvert->gem_info_dst[idx][SCMN_CB_PLANE].phy_addr; + imgb->a[SCMN_CB_PLANE] = (void*)(unsigned long)fimcconvert->gem_info_dst[idx][SCMN_CB_PLANE].usr_addr; + imgb->w[SCMN_CB_PLANE] = fimcconvert->dst_caps_width; + imgb->h[SCMN_CB_PLANE] = fimcconvert->dst_caps_height >> 1; + imgb->s[SCMN_CB_PLANE] = imgb->w[SCMN_CB_PLANE]; + imgb->e[SCMN_CB_PLANE] = imgb->h[SCMN_CB_PLANE]; + } else if (fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','4','2','0')) { + GST_INFO_OBJECT (fimcconvert, "OutBuf :: It's S420"); + imgb->cs = SCMN_CS_I420; + imgb->p[SCMN_CB_PLANE] = (void*)(unsigned long)fimcconvert->gem_info_dst[idx][SCMN_CB_PLANE].phy_addr; + imgb->a[SCMN_CB_PLANE] = (void*)(unsigned long)fimcconvert->gem_info_dst[idx][SCMN_CB_PLANE].usr_addr; + imgb->p[SCMN_CR_PLANE] = (void*)(unsigned long)fimcconvert->gem_info_dst[idx][SCMN_CR_PLANE].phy_addr; + imgb->a[SCMN_CR_PLANE] = (void*)(unsigned long)fimcconvert->gem_info_dst[idx][SCMN_CR_PLANE].usr_addr; + imgb->w[SCMN_CB_PLANE] = imgb->w[SCMN_CR_PLANE] = fimcconvert->dst_caps_width; + imgb->h[SCMN_CB_PLANE] = imgb->h[SCMN_CR_PLANE] = fimcconvert->dst_caps_height >> 2; + imgb->s[SCMN_CB_PLANE] = imgb->w[SCMN_CB_PLANE]; + imgb->e[SCMN_CB_PLANE] = imgb->h[SCMN_CB_PLANE]; + imgb->s[SCMN_CR_PLANE] = imgb->w[SCMN_CR_PLANE]; + imgb->e[SCMN_CR_PLANE] = imgb->h[SCMN_CR_PLANE]; + } else if (fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','U','Y','V') + || fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','U','Y','2') ) { + GST_INFO_OBJECT (fimcconvert, "OutBuf :: It's SUYV, SUY2"); + imgb->cs = SCMN_CS_YUYV; + } else if (fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','Y','V','Y')) { + GST_INFO_OBJECT (fimcconvert, "OutBuf :: It's SYVY"); + imgb->cs = SCMN_CS_UYVY; + } else { + free(imgb); + GST_ERROR_OBJECT (fimcconvert, "OutBuf :: can not support this format (%d)",fimcconvert->dst_format_gst); + return FALSE; + } + GST_DEBUG_OBJECT (fimcconvert, "OutBuf :: y_phy_addr(0x%x), cb_phy_addr(0x%x), cr_phy_addr(0x%x)",imgb->p[0],imgb->p[1],imgb->p[2]); + + } else if (fimcconvert->buf_share_method_type == BUF_SHARE_METHOD_FD || + fimcconvert->buf_share_method_type == BUF_SHARE_METHOD_TIZEN_BUFFER) { + + if (fimcconvert->buf_share_method_type == BUF_SHARE_METHOD_FD) { + imgb->dma_buf_fd[SCMN_Y_PLANE] = fimcconvert->gem_info_dst[idx][SCMN_Y_PLANE].dma_buf_fd; + } else { + imgb->bo[SCMN_Y_PLANE] = fimcconvert->gem_info_dst[idx][SCMN_Y_PLANE].bo; + } + imgb->a[SCMN_Y_PLANE] = (void*)(unsigned long)fimcconvert->gem_info_dst[idx][SCMN_Y_PLANE].usr_addr; + imgb->w[SCMN_Y_PLANE] = fimcconvert->dst_caps_width; + imgb->h[SCMN_Y_PLANE] = fimcconvert->dst_caps_height; + imgb->s[SCMN_Y_PLANE] = imgb->w[SCMN_Y_PLANE]; + imgb->e[SCMN_Y_PLANE] = imgb->h[SCMN_Y_PLANE]; + imgb->buf_share_method = fimcconvert->buf_share_method_type; + + if (fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','T','1','2') + || fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','N','1','2')) { + if (fimcconvert->buf_share_method_type == BUF_SHARE_METHOD_FD) { + imgb->dma_buf_fd[SCMN_CB_PLANE] = fimcconvert->gem_info_dst[idx][SCMN_CB_PLANE].dma_buf_fd; + } else { + imgb->bo[SCMN_CB_PLANE] = fimcconvert->gem_info_dst[idx][SCMN_CB_PLANE].bo; + } + if (fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','N','1','2')) { + GST_INFO_OBJECT (fimcconvert, "OutBuf :: It's SN12"); + imgb->cs = SCMN_CS_NV12; + } else { + GST_INFO_OBJECT (fimcconvert, "OutBuf :: It's ST12"); + imgb->cs = SCMN_CS_NV12_T64X32; + } + imgb->a[SCMN_CB_PLANE] = (void*)(unsigned long)fimcconvert->gem_info_dst[idx][SCMN_CB_PLANE].usr_addr; + imgb->w[SCMN_CB_PLANE] = fimcconvert->dst_caps_width; + imgb->h[SCMN_CB_PLANE] = fimcconvert->dst_caps_height >> 1; + imgb->s[SCMN_CB_PLANE] = imgb->w[SCMN_CB_PLANE]; + imgb->e[SCMN_CB_PLANE] = imgb->h[SCMN_CB_PLANE]; + } else if (fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','4','2','0')) { + GST_INFO_OBJECT (fimcconvert, "OutBuf :: It's S420"); + if (fimcconvert->buf_share_method_type == BUF_SHARE_METHOD_FD) { + imgb->dma_buf_fd[SCMN_CB_PLANE] = fimcconvert->gem_info_dst[idx][SCMN_CB_PLANE].dma_buf_fd; + imgb->dma_buf_fd[SCMN_CR_PLANE] = fimcconvert->gem_info_dst[idx][SCMN_CR_PLANE].dma_buf_fd; + } else { + imgb->bo[SCMN_CB_PLANE] = fimcconvert->gem_info_dst[idx][SCMN_CB_PLANE].bo; + imgb->bo[SCMN_CR_PLANE] = fimcconvert->gem_info_dst[idx][SCMN_CR_PLANE].bo; + } + imgb->cs = SCMN_CS_I420; + imgb->a[SCMN_CB_PLANE] = (void*)(unsigned long)fimcconvert->gem_info_dst[idx][SCMN_CB_PLANE].usr_addr; + imgb->a[SCMN_CR_PLANE] = (void*)(unsigned long)fimcconvert->gem_info_dst[idx][SCMN_CR_PLANE].usr_addr; + imgb->w[SCMN_CB_PLANE] = imgb->w[SCMN_CR_PLANE] = fimcconvert->dst_caps_width; + imgb->h[SCMN_CB_PLANE] = imgb->h[SCMN_CR_PLANE] = fimcconvert->dst_caps_height >> 2; + imgb->s[SCMN_CB_PLANE] = imgb->w[SCMN_CB_PLANE]; + imgb->e[SCMN_CB_PLANE] = imgb->h[SCMN_CB_PLANE]; + imgb->s[SCMN_CR_PLANE] = imgb->w[SCMN_CR_PLANE]; + imgb->e[SCMN_CR_PLANE] = imgb->h[SCMN_CR_PLANE]; + } else if (fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','U','Y','V') + || fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','U','Y','2') ) { + GST_INFO_OBJECT (fimcconvert, "OutBuf :: It's SUYV, SUY2"); + imgb->cs = SCMN_CS_YUYV; + } else if (fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','Y','V','Y')) { + GST_INFO_OBJECT (fimcconvert, "OutBuf :: It's SYVY"); + imgb->cs = SCMN_CS_UYVY; + } else if (fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','R','3','2')) { + GST_INFO_OBJECT (fimcconvert, "OutBuf :: It's SR32"); + imgb->cs = SCMN_CS_ARGB8888; + } else { + free(imgb); + GST_ERROR_OBJECT (fimcconvert, "OutBuf :: can not support this format (%d)",fimcconvert->dst_format_gst); + return FALSE; + } + + if (fimcconvert->buf_share_method_type == BUF_SHARE_METHOD_FD) { + GST_DEBUG_OBJECT (fimcconvert, "OutBuf :: y_fd(%d), cb_fd(%d), cr_fd(%d)",imgb->dma_buf_fd[SCMN_Y_PLANE],imgb->dma_buf_fd[SCMN_CB_PLANE],imgb->dma_buf_fd[SCMN_CR_PLANE]); + } else { + GST_DEBUG_OBJECT (fimcconvert, "OutBuf :: y_bo(%p), cb_bo(%p), cr_bo(%p)",imgb->bo[SCMN_Y_PLANE],imgb->bo[SCMN_CB_PLANE],imgb->bo[SCMN_CR_PLANE]); + } + +#ifdef USE_DETECT_JPEG + /* allocation memory and setting for JPEG */ + if (fimcconvert->jpeg_data && fimcconvert->jpeg_data_size != 0) { + imgb->jpeg_data = malloc((size_t)fimcconvert->jpeg_data_size); + if (!imgb->jpeg_data) { + GST_ERROR_OBJECT (fimcconvert, "OutBuf :: failed to malloc() for JPEG data, size(%d)", fimcconvert->jpeg_data_size); + } else { + GST_INFO_OBJECT (fimcconvert, "OutBuf :: JPEG data is detected, data(%p), size(%d), DO MEMCPY", imgb->jpeg_data, fimcconvert->jpeg_data_size); + imgb->jpeg_size = fimcconvert->jpeg_data_size; + memcpy ((void*)(unsigned int)imgb->jpeg_data, fimcconvert->jpeg_data, fimcconvert->jpeg_data_size); + } + } +#endif + + } else { + free(imgb); + GST_ERROR_OBJECT (fimcconvert, "OutBuf :: invalid buffer sharing method type (%d)", fimcconvert->buf_share_method_type); + return FALSE; + } + + /* Set SCMN_IMGB pointer */ + gst_buffer_prepend_memory(buf, gst_memory_new_wrapped(GST_MEMORY_FLAG_READONLY, + imgb, + sizeof(*imgb), + 0, + sizeof(*imgb), + imgb, + free)); + + return TRUE; +} + +static guint32 +gst_fimcconvert_get_drm_format(GstCaps *caps) +{ + GstStructure *structure = NULL; + GstVideoInfo video_info; + + structure = gst_caps_get_structure(caps, 0); + if (gst_structure_has_name (structure, "video/x-raw")) { + gst_video_info_from_caps(&video_info, caps); + if (GST_VIDEO_INFO_IS_RGB(&video_info)) { + gint bpp = 0; + + if (!gst_structure_get_int (structure, "bpp", &bpp) || (bpp & 0x07) != 0) + return 0; + if (bpp == 16) { + GST_INFO ("It's RGB565, bpp(16)"); + return DRM_FORMAT_RGB565; + } else if (bpp == 24) { + GST_INFO ("It's RGB888, bpp(24)"); + return DRM_FORMAT_RGB888; + } else if (bpp == 32) { + #if 1 + GST_INFO ("It's XRGB8888, bpp(32)"); + return DRM_FORMAT_XRGB8888; + #else + /* NOTE : BGRA8888 test required if kernel support it */ + GST_INFO ("It's BGRA8888, bpp(32)"); + return DRM_FORMAT_BGRA8888; + #endif + } else { + GST_ERROR ("bpp is not valid. bpp(%d)", bpp); + return 0; + } + } else if (GST_VIDEO_INFO_IS_YUV(&video_info)) { + const gchar *format = GST_VIDEO_INFO_NAME(&video_info); + if (!format) { + GST_ERROR ("can not get format in gst structure"); + return 0; + } + + GST_INFO ("format - %s", format); + if (strcmp(format, "ST12") == 0) + return DRM_FORMAT_NV12MT; + else if (strcmp(format, "SN12") == 0 + || strcmp(format, "NV12") == 0) + return DRM_FORMAT_NV12; + else if (strcmp(format, "SUYV") == 0 + || strcmp(format, "YUYV") == 0 + || strcmp(format, "SUY2") == 0 + || strcmp(format, "YUY2") == 0) + return DRM_FORMAT_YUYV; + else if (strcmp(format, "I420") == 0 + || strcmp(format, "S420") == 0) + return DRM_FORMAT_YUV420; + else if (strcmp(format, "ITLV") == 0 + || strcmp(format, "SYVY") == 0 + || strcmp(format, "UYVY") == 0) + return DRM_FORMAT_UYVY; + else { + GST_WARNING ("not supported format(%s)", format); + return 0; + } + } + } + return 0; +} + +static GstCaps * +gst_fimcconvert_transform_caps(GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, GstCaps *filter) +{ + GstCaps *template; + GstCaps *ret_caps; + GstPad *otherpad; + + if (direction == GST_PAD_SRC) { + otherpad = trans->sinkpad; + } else if (direction == GST_PAD_SINK) { + otherpad = trans->srcpad; + } else { + return NULL; + } + + template = gst_caps_copy(gst_pad_get_pad_template_caps(otherpad)); + ret_caps = gst_caps_intersect(caps, template); + ret_caps = gst_caps_make_writable(ret_caps); + gst_caps_append(ret_caps, template); + + return filter ? gst_caps_intersect(ret_caps, filter) : ret_caps; +} + +// fixate_caps function is from videoscale plugin +static GstCaps* +gst_fimcconvert_fixate_caps(GstBaseTransform *base, GstPadDirection direction, GstCaps *caps, GstCaps *othercaps) +{ + GstStructure *ins, *outs; + const GValue *from_par, *to_par; + GstFimcConvert *fimcconvert; + + g_return_val_if_fail(gst_caps_is_fixed(caps), NULL); + + fimcconvert = GST_FIMCCONVERT(base); + + GST_DEBUG_OBJECT(base, "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); + + from_par = gst_structure_get_value(ins, "pixel-aspect-ratio"); + to_par = gst_structure_get_value(outs, "pixel-aspect-ratio"); + + /* we have both PAR but they might not be fixated */ + if (from_par && to_par) { + gint from_w, from_h, from_par_n, from_par_d, to_par_n, to_par_d; + gint count = 0, w = 0, h = 0; + guint num, den; + + /* from_par should be fixed */ + g_return_val_if_fail(gst_value_is_fixed(from_par), NULL); + + from_par_n = gst_value_get_fraction_numerator(from_par); + from_par_d = gst_value_get_fraction_denominator(from_par); + + /* fixate the out PAR */ + if (!gst_value_is_fixed(to_par)) { + GST_DEBUG_OBJECT(base, "fixating to_par to %dx%d", from_par_n, from_par_d); + gst_structure_fixate_field_nearest_fraction(outs, "pixel-aspect-ratio", from_par_n, from_par_d); + } + + to_par_n = gst_value_get_fraction_numerator(to_par); + to_par_d = gst_value_get_fraction_denominator(to_par); + + /* if both width and height are already fixed, we can't do anything + * about it anymore */ + if (gst_structure_get_int(outs, "width", &w)) + ++count; + if (gst_structure_get_int(outs, "height", &h)) + ++count; + if (count == 2) { + GST_DEBUG_OBJECT(base, "dimensions already set to %dx%d, not fixating", w, h); + return othercaps; + } + + gst_structure_get_int(ins, "width", &from_w); + gst_structure_get_int(ins, "height", &from_h); + + if (!gst_video_calculate_display_ratio(&num, &den, from_w, from_h, from_par_n, from_par_d, to_par_n, to_par_d)) { + GST_ELEMENT_ERROR(base, CORE, NEGOTIATION,(NULL), ("Error calculating the output scaled size - integer overflow")); + return NULL; + } + + GST_DEBUG_OBJECT(base, "scaling input with %dx%d and PAR %d/%d to output PAR %d/%d", from_w, from_h, from_par_n, from_par_d, to_par_n, to_par_d); + GST_DEBUG_OBJECT(base, "resulting output should respect ratio of %d/%d", num, den); + + /* now find a width x height that respects this display ratio. + * prefer those that have one of w/h the same as the incoming video + * using wd / hd = num / den */ + + /* if one of the output width or height is fixed, we work from there */ + if (h) { + GST_DEBUG_OBJECT(base, "height is fixed,scaling width"); + w =(guint) gst_util_uint64_scale_int(h, num, den); + } else if (w) { + GST_DEBUG_OBJECT(base, "width is fixed, scaling height"); + h =(guint) gst_util_uint64_scale_int(w, den, num); + } else { + /* none of width or height is fixed, figure out both of them based only on + * the input width and height */ + /* check hd / den is an integer scale factor, and scale wd with the PAR */ + if (from_h % den == 0) { + GST_DEBUG_OBJECT(base, "keeping video height"); + h = from_h; + w =(guint) gst_util_uint64_scale_int(h, num, den); + } else if (from_w % num == 0) { + GST_DEBUG_OBJECT(base, "keeping video width"); + w = from_w; + h =(guint) gst_util_uint64_scale_int(w, den, num); + } else { + GST_DEBUG_OBJECT(base, "approximating but keeping video height"); + h = from_h; + w =(guint) gst_util_uint64_scale_int(h, num, den); + } + } + GST_DEBUG_OBJECT(base, "scaling to %dx%d", w, h); + + /* now fixate */ + gst_structure_fixate_field_nearest_int(outs, "width", w); + gst_structure_fixate_field_nearest_int(outs, "height", h); + } else { + gint width = 0; + gint height = 0; + gint rotate = 0; + gint flip = 0; + GValue *framerate = NULL; + + if (gst_structure_get_int(outs, "rotate", &rotate)) { + switch (rotate) { + case 0: + case 90: + case 180: + case 270: + fimcconvert->rotate_ang = rotate; + GST_INFO_OBJECT(fimcconvert, "set rotate(%d) from outcaps", rotate); + break; + default: + break; + } + } + if (gst_structure_get_int(outs, "flip", &flip)) { + switch (flip) { + case 0: + case 1: + case 2: + fimcconvert->dst_flip = flip; + GST_INFO_OBJECT(fimcconvert, "set flip(%d) from outcaps", flip); + break; + default: + break; + } + } + framerate = gst_structure_get_value(ins, "framerate"); + if (framerate) { + if (gst_structure_has_field(outs, "framerate")) { + gst_structure_set_value (outs, "framerate", framerate); + } + } + + if (gst_structure_has_field(outs, "width") && gst_structure_has_field(outs, "height")) { + if (fimcconvert->dst_width && fimcconvert->dst_height) { + if (gst_structure_fixate_field_nearest_int(outs, "width", fimcconvert->dst_width)) { + GST_INFO_OBJECT(fimcconvert, "set width size from property value(%d), rotate(%d)", fimcconvert->dst_width, fimcconvert->rotate_ang); + } else { + GST_WARNING_OBJECT(fimcconvert, "fixate_field_nearest_int(width) failed"); + } + if (gst_structure_fixate_field_nearest_int(outs, "height", fimcconvert->dst_height)) { + GST_INFO_OBJECT(fimcconvert, "set height size from property value(%d), rotate(%d)", fimcconvert->dst_height, fimcconvert->rotate_ang); + } else { + GST_WARNING_OBJECT(fimcconvert, "fixate_field_nearest_int(height) failed"); + } + } else { + if ((fimcconvert->rotate_ang == 90) || (fimcconvert->rotate_ang == 270)) { + if (gst_structure_get_int(outs, "width", &width) + && gst_structure_get_int(outs, "height", &height)) { /* outcaps already have width/height */ + /* do nothing */ + } else { + if (gst_structure_get_int(ins, "width", &width) + && gst_structure_get_int(ins, "height", &height)) { /* outcaps does not have width/height, use incaps */ + if (gst_structure_fixate_field_nearest_int(outs, "width", height)) { + GST_INFO_OBJECT(fimcconvert, "set width size from caps value(%d), rotate(%d)", height, fimcconvert->rotate_ang); + } else { + GST_WARNING_OBJECT(fimcconvert, "fixate_field_nearest_int(width) failed"); + } + if (gst_structure_fixate_field_nearest_int(outs, "height", width)) { + GST_INFO_OBJECT(fimcconvert, "set height size from caps value(%d), rotate(%d)", width, fimcconvert->rotate_ang); + } else { + GST_WARNING_OBJECT(fimcconvert, "fixate_field_nearest_int(height) failed"); + } + } else { + GST_ERROR_OBJECT(fimcconvert, "can not get width/height from incaps"); + return NULL; + } + } + } else { + if (gst_structure_get_int(outs, "width", &width) + && gst_structure_get_int(outs, "height", &height)) { /* outcaps already have width/height */ + /* do nothing */ + } else { + if (gst_structure_get_int(ins, "width", &width) + && gst_structure_get_int(ins, "height", &height)) { /* outcaps does not have width/height, use incaps */ + if (gst_structure_fixate_field_nearest_int(outs, "width", width)) { + GST_INFO_OBJECT(fimcconvert, "set width size from caps value(%d)", width); + } else { + GST_WARNING_OBJECT(fimcconvert, "fixate_field_nearest_int(width) failed"); + } + if (gst_structure_fixate_field_nearest_int(outs, "height", height)) { + GST_INFO_OBJECT(fimcconvert, "set height size from caps value(%d)", height); + } else { + GST_WARNING_OBJECT(fimcconvert, "fixate_field_nearest_int(height) failed"); + } + } else { + GST_ERROR_OBJECT(fimcconvert, "can not get width/height from incaps"); + return NULL; + } + } + } + } + } else { + GST_ERROR_OBJECT(fimcconvert, "outcaps does not have width/height fields"); + return NULL; + } + } + + GST_INFO_OBJECT(base, "fixated othercaps to %" GST_PTR_FORMAT, othercaps); + return othercaps; +} + +static gboolean +gst_fimcconvert_set_caps(GstBaseTransform *trans, GstCaps *in, GstCaps *out) +{ + GstFimcConvert *fimcconvert = NULL; + GstStructure *structure = NULL; + const gchar *format_name = NULL; + gchar *str_in = NULL; + gchar *str_out = NULL; + const gchar *src_format_gst = NULL; + gint src_caps_width = 0; + gint src_caps_height = 0; + + fimcconvert = GST_FIMCCONVERT(trans); + str_in = gst_caps_to_string(in); + if(str_in == NULL) { + GST_ERROR_OBJECT(fimcconvert, "gst_caps_to_string() returns NULL..."); + return FALSE; + } + GST_WARNING_OBJECT(fimcconvert, "[incaps] %s", str_in); + + str_out = gst_caps_to_string(out); + if(str_out == NULL) { + GST_ERROR_OBJECT(fimcconvert, "gst_caps_to_string() returns NULL..."); + g_free (str_in); + return FALSE; + } + GST_WARNING_OBJECT(fimcconvert, "[outcaps] %s", str_out); + + /* get src width/height/format of video frame */ + structure = gst_caps_get_structure(in, 0); + if (!gst_structure_get_int (structure, "width", &src_caps_width) || !gst_structure_get_int (structure, "height", &src_caps_height)) { + GST_ERROR_OBJECT (fimcconvert, "input frame width or height is not set..."); + return FALSE; + } + if (!(src_format_gst = gst_structure_get_string (structure, "format"))) { + GST_DEBUG_OBJECT (fimcconvert, "format(src) is not set...it may be rgb series"); + } + + if ( strcmp(src_format_gst, "SN12") != 0 && + strcmp(src_format_gst, "ST12") != 0 && + strcmp(src_format_gst, "S420") != 0 && + strcmp(src_format_gst, "SUYV") != 0 && + strcmp(src_format_gst, "SUY2") != 0 && + strcmp(src_format_gst, "SYVY") != 0 && + strcmp(src_format_gst, "ITLV") != 0 && + strcmp(src_format_gst, "SR32") != 0 ) { + fimcconvert->is_src_format_std = TRUE; + } + + /* determine whether if incaps is same as outcaps */ + if ( !strncmp(str_in, str_out, strlen(str_in)) + && ( (!fimcconvert->dst_width && !fimcconvert->dst_height) || ((fimcconvert->dst_width == src_caps_width) && (fimcconvert->dst_height == src_caps_height)) ) + && !fimcconvert->dst_flip && !fimcconvert->rotate_ang ) { + GST_LOG_OBJECT(fimcconvert, "incaps is same as outcaps"); + fimcconvert->is_same_caps = TRUE; + g_free (str_in); + g_free (str_out); + return TRUE; + } else { + fimcconvert->is_same_caps = FALSE; + g_free (str_in); + g_free (str_out); + } + + /* set src width/height of video frame */ + fimcconvert->src_caps_width = src_caps_width; + fimcconvert->src_caps_height = src_caps_height; + fimcconvert->src_format_drm = gst_fimcconvert_get_drm_format(in); + GST_INFO_OBJECT(fimcconvert, "[set src_caps] width(%d) height(%d)", fimcconvert->src_caps_width, fimcconvert->src_caps_height); + + /* set dst width/height of video frame */ + if (!fimcconvert->dst_width || !fimcconvert->dst_height) { + structure = gst_caps_get_structure(out, 0); + if (!gst_structure_get_int (structure, "width", &fimcconvert->dst_caps_width) || !gst_structure_get_int (structure, "height", &fimcconvert->dst_caps_height) ) { + GST_ERROR_OBJECT (fimcconvert, "output frame width or height is not set..."); + return FALSE; + } + } + fimcconvert->dst_format_drm = gst_fimcconvert_get_drm_format(out); + format_name = gst_structure_get_string (structure, "format"); + fimcconvert->dst_format_gst = gst_video_format_to_fourcc(gst_video_format_from_string(format_name)); + if (!fimcconvert->dst_format_gst) { + GST_DEBUG_OBJECT (fimcconvert, "format(dst) is not set...it may be rgb series"); + } + + GST_INFO_OBJECT(fimcconvert, "[set dst_caps] width(%d) height(%d)", fimcconvert->dst_caps_width, fimcconvert->dst_caps_height); + if (fimcconvert->dst_format_gst) { + GST_INFO_OBJECT(fimcconvert, "[set dst_caps] format(%c%c%c%c)", fimcconvert->dst_format_gst, fimcconvert->dst_format_gst>>8, + fimcconvert->dst_format_gst>>16, fimcconvert->dst_format_gst>>24); + } + + gst_fimcconvert_reset(fimcconvert); + + return TRUE; +} + +static gboolean +gst_fimcconvert_get_unit_size(GstBaseTransform *trans, GstCaps *caps, guint *size) +{ + GstStructure *structure; + gint width, height; + gint bytes_per_pixel; + gint stride; + GstFimcConvert *fimcconvert; + + fimcconvert = GST_FIMCCONVERT(trans); + + structure = gst_caps_get_structure (caps, 0); + if (!gst_structure_get_int (structure, "width", &width) ||!gst_structure_get_int (structure, "height", &height)) { + return FALSE; + } + + if (gst_structure_has_name (structure, "video/x-raw")) { + GstVideoInfo video_info; + gst_video_info_from_caps(&video_info, caps); + if (GST_VIDEO_INFO_IS_RGB(&video_info)) { + gint bpp = 0; + GST_DEBUG_OBJECT (fimcconvert, "Output format is in RGB..."); + if (!gst_structure_get_int (structure, "bpp", &bpp) || (bpp & 0x07) != 0) { + return FALSE; + } + bytes_per_pixel = bpp / 8; + stride = ALIGN_TO_4B(width) * bytes_per_pixel; + *size = stride * ALIGN_TO_4B(height); + } else if (GST_VIDEO_INFO_IS_YUV(&video_info)) { + gint32 width = 0; + gint32 height = 0; + + GST_DEBUG_OBJECT (fimcconvert,"format is in YUV..."); + if (!gst_structure_get_int (structure, "width", &width)) { + return FALSE; + } + if (!gst_structure_get_int (structure, "height", &height)) { + return FALSE; + } + + switch (gst_video_format_to_fourcc(GST_VIDEO_INFO_FORMAT(&video_info))) { + case GST_MAKE_FOURCC('S', 'T', '1', '2'): + case GST_MAKE_FOURCC('S', 'N', '1', '2'): + case GST_MAKE_FOURCC('N', 'V', '1', '2'): + case GST_MAKE_FOURCC('S', '4', '2', '0'): + case GST_MAKE_FOURCC('I', '4', '2', '0'): + *size = (width * height * 3) >> 1; + break; + case GST_MAKE_FOURCC('I', 'T', 'L', 'V'): + case GST_MAKE_FOURCC('S', 'U', 'Y', '2'): + case GST_MAKE_FOURCC('Y', 'U', 'Y', '2'): + case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'): + case GST_MAKE_FOURCC('Y', 'U', 'Y', 'V'): + case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'): + case GST_MAKE_FOURCC('U', 'Y', 'V', 'Y'): + *size = (width * height * 2); + break; + default: + GST_DEBUG_OBJECT (fimcconvert, "Not handling selected YUV format..."); + return FALSE; + } + } + } + GST_DEBUG_OBJECT (fimcconvert, "Buffer size is %d", *size); + + return TRUE; +} + +static GstFlowReturn +gst_fimcconvert_prepare_output_buffer(GstBaseTransform *trans, GstBuffer *in_buf, GstBuffer **out_buf) +{ + gboolean ret = TRUE; + guint out_size = 0; + guint in_size = 0; + GstFimcConvert *fimcconvert = GST_FIMCCONVERT(trans); + GstCaps *out_caps; + GstCaps *in_caps; + GstFimcConvertBuffer *fimcconvert_buffer = NULL; + + GST_DEBUG ("[START]"); + + if (fimcconvert->is_same_caps) { + GST_INFO ("in/out caps are same. skipping it"); + GST_DEBUG ("[END]"); + return GST_FLOW_OK; + } + + g_mutex_lock (fimcconvert->fd_lock); + + in_caps = gst_pad_get_current_caps (trans->sinkpad); + out_caps = gst_pad_get_current_caps (trans->srcpad); + + ret = gst_fimcconvert_get_unit_size(trans, in_caps, &in_size); + if (ret == FALSE) { + GST_ERROR ("ERROR in _get_unit_size from in_caps..."); + return GST_FLOW_ERROR; + } + ret = gst_fimcconvert_get_unit_size(trans, out_caps, &out_size); + if (ret == FALSE) { + GST_ERROR ("ERROR in _get_unit_size from out_caps..."); + return GST_FLOW_ERROR; + } + + GST_INFO ("input caps :: %s", gst_caps_to_string(in_caps)); + GST_INFO ("output caps :: %s", gst_caps_to_string(out_caps)); + GST_DEBUG ("In buffer size = %d", in_size); + GST_DEBUG ("Out buffer size = %d", out_size); + + fimcconvert->dst_buf_size = out_size; + + + fimcconvert_buffer = gst_fimcconvert_buffer_new(fimcconvert, out_size); + *out_buf = fimcconvert_buffer->buffer; + if (*out_buf == NULL) { + GST_ERROR ("ERROR in creating outbuf..."); + return GST_FLOW_ERROR; + } + + gst_buffer_copy_into(*out_buf, in_buf, GST_BUFFER_COPY_METADATA, 0, -1); + GST_LOG ("out ts : %"GST_TIME_FORMAT" and out dur : %"GST_TIME_FORMAT, + GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(*out_buf)), GST_TIME_ARGS(GST_BUFFER_DURATION(*out_buf))); + GST_DEBUG ("output buffer ready"); + gst_caps_unref(out_caps); + gst_buffer_append_memory(*out_buf, gst_memory_new_wrapped(GST_MEMORY_FLAG_READONLY, + fimcconvert_buffer, + sizeof(*fimcconvert_buffer), + 0, + sizeof(*fimcconvert_buffer), + fimcconvert_buffer, + (GDestroyNotify)gst_fimcconvert_buffer_finalize)); + g_mutex_unlock (fimcconvert->fd_lock); + + GST_DEBUG ("[END]"); + + return GST_FLOW_OK; +} + +static gboolean +gst_fimcconvert_check_new_src(GstFimcConvert *fimcconvert, GstBuffer *inbuf) +{ + SCMN_IMGB *imgb = NULL; + GstMemory *imgb_memory = NULL; + GstMapInfo imgb_info = GST_MAP_INFO_INIT; + int i = 0; + guint phy_addr = 0; + gint fd = 0; + tbm_bo bo = 0; + + g_return_val_if_fail (GST_IS_FIMCCONVERT (fimcconvert), FALSE); + + if (!fimcconvert->is_src_format_std) { + if (gst_buffer_n_memory(inbuf) > 2) { + imgb_memory = gst_buffer_peek_memory(inbuf, 1); + gst_memory_map(imgb_memory, &imgb_info, GST_MAP_READ); + imgb = (SCMN_IMGB *)imgb_info.data; + gst_memory_unmap(imgb_memory, &imgb_info); + if (imgb->buf_share_method == BUF_SHARE_METHOD_PADDR) { + GST_LOG_OBJECT (fimcconvert, "Samsung colorspace format, PADDR type"); + phy_addr = (guint)imgb->p[SCMN_Y_PLANE]; + if (phy_addr) { + for (i = 0; i < MAX_SRC_BUF_NUM; i++) { + if (fimcconvert->gem_info_src[i][SCMN_Y_PLANE].gem_handle) { + if (phy_addr == fimcconvert->gem_info_src[i][SCMN_Y_PLANE].phy_addr) { + return FALSE; + } + } else { + return TRUE; + } + } + } else { + GST_WARNING_OBJECT (fimcconvert, "invalid value : imgb->p[SCMN_Y_PLANE] = 0"); + fimcconvert->do_skip = TRUE; + return FALSE; + } + } else if (imgb->buf_share_method == BUF_SHARE_METHOD_FD) { + GST_LOG_OBJECT (fimcconvert, "Samsung colorspace format, FD type"); + fd = imgb->dma_buf_fd[SCMN_Y_PLANE]; + if (fd) { + for (i = 0; i < MAX_SRC_BUF_NUM; i++) { + if (fimcconvert->gem_info_src[i][SCMN_Y_PLANE].dma_buf_fd) { + if (fd == fimcconvert->gem_info_src[i][SCMN_Y_PLANE].dma_buf_fd) { + return FALSE; + } + } else { + return TRUE; + } + } + } else { + GST_WARNING_OBJECT (fimcconvert, "invalid value : imgb->dma_buf_fd[SCMN_Y_PLANE] = 0"); + fimcconvert->do_skip = TRUE; + return FALSE; + } + } else if (imgb->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER) { + GST_LOG_OBJECT (fimcconvert, "Samsung colorspace format, TBM type"); + bo = imgb->bo[SCMN_Y_PLANE]; + if (bo) { + for (i = 0; i < MAX_SRC_BUF_NUM; i++) { + if (fimcconvert->gem_info_src[i][SCMN_Y_PLANE].bo) { + if (bo == fimcconvert->gem_info_src[i][SCMN_Y_PLANE].bo) { + return FALSE; + } + } else { + return TRUE; + } + } + } else { + GST_WARNING_OBJECT (fimcconvert, "invalid value : imgb->bo[SCMN_Y_PLANE] = 0"); + fimcconvert->do_skip = TRUE; + return FALSE; + } + } else { + GST_ERROR_OBJECT (fimcconvert, "Samsung colorspace format, could not find BUF_SHARE_METHOD type"); + return FALSE; + } + } else { + GST_ERROR_OBJECT (fimcconvert, "Samsung colorspace format, could not get IMGB"); + return FALSE; + } + } else { + /* if a buffer passed from src plugin has a standard colorspace format, return TRUE */ + if (fimcconvert->src_buf_idx == SRC_BUF_NUM_FOR_STD_FMT) { + return FALSE; + } else { + return TRUE; + } + } + + GST_ERROR_OBJECT (fimcconvert, "should not reach here"); + return TRUE; +} + +static gboolean +gst_fimcconvert_drm_prepare_src_buf(GstFimcConvert *fimcconvert, GstBuffer *inbuf) +{ + SCMN_IMGB *imgb = NULL; + GstMemory *imgb_memory = NULL; + GstMapInfo imgb_info = GST_MAP_INFO_INIT; + guint src_idx = 0; + guint dst_idx = 0; + + struct drm_exynos_gem_phy_imp gem_src_phy_imp_y; + struct drm_exynos_gem_phy_imp gem_src_phy_imp_cb; + struct drm_exynos_gem_phy_imp gem_src_phy_imp_cr; + + g_return_val_if_fail (GST_IS_FIMCCONVERT (fimcconvert), FALSE); + + GST_DEBUG_OBJECT (fimcconvert, "[START]"); +#ifdef DEBUG_FOR_DV + if (total_converted_frame_count <= 10) { + GST_WARNING_OBJECT (fimcconvert, "[START]"); + } +#endif + + memset(&gem_src_phy_imp_y, 0x0, sizeof(struct drm_exynos_gem_phy_imp)); + memset(&gem_src_phy_imp_cb, 0x0, sizeof(struct drm_exynos_gem_phy_imp)); + memset(&gem_src_phy_imp_cr, 0x0, sizeof(struct drm_exynos_gem_phy_imp)); + + src_idx = fimcconvert->src_buf_idx; + dst_idx = fimcconvert->dst_buf_idx; + + GST_INFO_OBJECT (fimcconvert, "InBuf :: input buffer(%p)", inbuf); + + if (!fimcconvert->is_src_format_std) { + if (gst_buffer_n_memory(inbuf) > 2) { + imgb_memory = gst_buffer_peek_memory(inbuf, 1); + gst_memory_map(imgb_memory, &imgb_info, GST_MAP_READ); + imgb = (SCMN_IMGB *)imgb_info.data; + gst_memory_unmap(imgb_memory, &imgb_info); + GST_LOG_OBJECT (fimcconvert, "InBuf :: buf_share_method_type=%d (0:PADDR/1:FD/2:TBM)", imgb->buf_share_method); + + if (imgb->buf_share_method == BUF_SHARE_METHOD_PADDR) { + fimcconvert->buf_share_method_type = BUF_SHARE_METHOD_PADDR; + + switch (fimcconvert->src_format_drm) { + case DRM_FORMAT_NV12MT: + gem_src_phy_imp_y.phy_addr = (guint)imgb->p[0]; + gem_src_phy_imp_cb.phy_addr = (guint)imgb->p[1]; + gem_src_phy_imp_y.size = ALIGN_TO_8KB( ALIGN_TO_128B(fimcconvert->src_caps_width) * ALIGN_TO_32B(fimcconvert->src_caps_height)); + gem_src_phy_imp_cb.size = ALIGN_TO_8KB( ALIGN_TO_128B(fimcconvert->src_caps_width) * ALIGN_TO_32B(fimcconvert->src_caps_height>>1) ); + break; + case DRM_FORMAT_NV12: + gem_src_phy_imp_y.phy_addr = (guint)imgb->p[0]; + gem_src_phy_imp_cb.phy_addr = (guint)imgb->p[1]; + gem_src_phy_imp_y.size = imgb->w[0] * imgb->h[0]; + gem_src_phy_imp_cb.size = imgb->w[0] * imgb->h[0] >> 1; + break; + case DRM_FORMAT_UYVY: + case DRM_FORMAT_YUYV: + gem_src_phy_imp_y.phy_addr = (guint)imgb->p[0]; + gem_src_phy_imp_y.size = (imgb->w[0] * imgb->h[0]) << 1; + break; + case DRM_FORMAT_YUV420: + gem_src_phy_imp_y.phy_addr = (guint)imgb->p[0]; + gem_src_phy_imp_cb.phy_addr = (guint)imgb->p[1]; + gem_src_phy_imp_cr.phy_addr = (guint)imgb->p[2]; + gem_src_phy_imp_y.size = imgb->w[0] * imgb->h[0]; + gem_src_phy_imp_cb.size = imgb->w[0] * imgb->h[0] >> 2; + gem_src_phy_imp_cr.size = gem_src_phy_imp_cb.size; + break; + default: + GST_ERROR_OBJECT (fimcconvert, "Un-Supported Input color format..."); + return FALSE; + } + GST_INFO_OBJECT (fimcconvert, "InBuf :: It's a samsung extension format(%d)",fimcconvert->src_format_drm); + + if (!gem_src_phy_imp_y.phy_addr) { + GST_WARNING_OBJECT (fimcconvert, "gem_src_phy_imp_y.phy_addr is null.."); + fimcconvert->do_skip = TRUE; + return TRUE; + } + + /* Do DRM_IOCTL_EXYNOS_GEM_GET_PHY */ + if (fimcconvert->drm_fimc_fd) { + if (fimcconvert_drm_gem_import_phy_addr (fimcconvert->drm_fimc_fd, &gem_src_phy_imp_y)) { + return FALSE; + } + fimcconvert->gem_info_src[src_idx][SCMN_Y_PLANE].gem_handle = gem_src_phy_imp_y.gem_handle; + fimcconvert->gem_info_src[src_idx][SCMN_Y_PLANE].phy_addr = gem_src_phy_imp_y.phy_addr; + GST_DEBUG_OBJECT (fimcconvert, "InBuf :: gem_src_phy_imp_y[%d] : gem_handle=%d, y_phy_addr=0x%x", + src_idx, gem_src_phy_imp_y.gem_handle,(void*)(unsigned long)gem_src_phy_imp_y.phy_addr); + + switch (fimcconvert->src_format_drm) { + case DRM_FORMAT_NV12MT: + case DRM_FORMAT_NV12: + if (fimcconvert_drm_gem_import_phy_addr (fimcconvert->drm_fimc_fd, &gem_src_phy_imp_cb)) { + return FALSE; + } + fimcconvert->gem_info_src[src_idx][SCMN_CB_PLANE].gem_handle = gem_src_phy_imp_cb.gem_handle; + GST_DEBUG_OBJECT (fimcconvert, "InBuf :: gem_src_phy_imp_cb[%d] : gem_handle=%d, cb_phy_addr=0x%x", + src_idx, gem_src_phy_imp_cb.gem_handle,(void*)(unsigned long)gem_src_phy_imp_cb.phy_addr); + break; + + case DRM_FORMAT_YUV420: + if (fimcconvert_drm_gem_import_phy_addr (fimcconvert->drm_fimc_fd, &gem_src_phy_imp_cb)) { + return FALSE; + } + fimcconvert->gem_info_src[src_idx][SCMN_CB_PLANE].gem_handle = gem_src_phy_imp_cb.gem_handle; + GST_DEBUG_OBJECT (fimcconvert, "InBuf :: gem_src_phy_imp_cb[%d] : gem_handle=%d, cb_phy_addr=0x%x", + src_idx, gem_src_phy_imp_cb.gem_handle,(void*)(unsigned long)gem_src_phy_imp_cb.phy_addr); + if (fimcconvert_drm_gem_import_phy_addr (fimcconvert->drm_fimc_fd, &gem_src_phy_imp_cr)) { + return FALSE; + } + fimcconvert->gem_info_src[src_idx][SCMN_CR_PLANE].gem_handle = gem_src_phy_imp_cr.gem_handle; + GST_DEBUG_OBJECT (fimcconvert, "InBuf :: gem_src_phy_imp_cr[%d] : gem_handle=%d, cr_phy_addr=0x%x", + src_idx, gem_src_phy_imp_cr.gem_handle,(void*)(unsigned long)gem_src_phy_imp_cr.phy_addr); + break; + } + } else { + GST_ERROR_OBJECT (fimcconvert, "drm_fimc_fd is null.."); + return FALSE; + } + + } else if (imgb->buf_share_method == BUF_SHARE_METHOD_FD) { + int ret = 0; + int i = 0; + fimcconvert->buf_share_method_type = BUF_SHARE_METHOD_FD; + + /* convert dma-buf fd into drm gem handle */ + for (i = 0; i < SCMN_IMGB_MAX_PLANE-1; i++) { + fimcconvert->gem_info_src[src_idx][i].dma_buf_fd = imgb->dma_buf_fd[i]; + ret = fimcconvert_drm_convert_fd_to_gemhandle(fimcconvert->drm_fimc_fd, (int)imgb->dma_buf_fd[i], &fimcconvert->gem_info_src[src_idx][i].gem_handle); + if (ret) { + return FALSE; + } + } + GST_DEBUG_OBJECT (fimcconvert, "InBuf :: gem_info_src[%d] : gem_handle_y=%u, gem_handle_cb=%u, gem_handle_cr=%u", src_idx, + fimcconvert->gem_info_src[src_idx][SCMN_Y_PLANE].gem_handle, fimcconvert->gem_info_src[src_idx][SCMN_CB_PLANE].gem_handle, + fimcconvert->gem_info_src[src_idx][SCMN_CR_PLANE].gem_handle); + + } else if (imgb->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER) { + int i = 0; + tbm_bo_handle bo_handle_gem; + + fimcconvert->buf_share_method_type = BUF_SHARE_METHOD_TIZEN_BUFFER; + + /* convert bo into drm gem handle */ + for (i = 0; i < SCMN_IMGB_MAX_PLANE-1; i++) { + if (imgb->bo[i] > 0) { + GST_LOG_OBJECT(fimcconvert,"imgb->bo[%d] = %p", i, imgb->bo[i]); + fimcconvert->gem_info_src[src_idx][i].bo = imgb->bo[i]; + FIMCCONVERT_TBM_BO_GET_GEM_HANDLE( imgb->bo[i], bo_handle_gem ); + fimcconvert->gem_info_src[src_idx][i].gem_handle = bo_handle_gem.u32; + } + } + GST_DEBUG_OBJECT (fimcconvert, "InBuf :: gem_info_src[%d] : gem_handle_y=%u, gem_handle_cb=%u, gem_handle_cr=%u", src_idx, + fimcconvert->gem_info_src[src_idx][SCMN_Y_PLANE].gem_handle, fimcconvert->gem_info_src[src_idx][SCMN_CB_PLANE].gem_handle, + fimcconvert->gem_info_src[src_idx][SCMN_CR_PLANE].gem_handle); + } else { + GST_ERROR_OBJECT (fimcconvert, "InBuf :: Unknown BUF_SHARE_METHOD"); + return FALSE; + } + } else { + GST_WARNING_OBJECT (fimcconvert, "InBuf :: could not get imgb from inbuf.. let this frame skip.."); + fimcconvert->do_skip = TRUE; + return FALSE; + } + } else { + /* for a standard colorspace format */ + fimcconvert->src_buf_size = gst_buffer_get_size(inbuf); + + GST_INFO_OBJECT (fimcconvert, "InBuf :: It's a standard format(%d)", fimcconvert->src_format_drm); + GST_DEBUG_OBJECT (fimcconvert, "InBuf :: Prepare for memory copy, src data size(%d)", fimcconvert->src_buf_size); + + /* Make gem handle and do map for src buffer */ + if (!gst_fimcconvert_tbm_create_and_map_bo(fimcconvert, FIMCCONVERT_GEM_FOR_SRC)) { + return FALSE; + } + + /* determine buf_share_method_type */ + if (!fimcconvert->is_drm_inited) { + if (fimcconvert_drm_gem_get_phy_addr(fimcconvert->drm_fimc_fd, fimcconvert->gem_info_src_normal_fmt[src_idx].gem_handle, &fimcconvert->gem_info_src_normal_fmt[src_idx].phy_addr)) { +#ifdef USE_TBM + fimcconvert->buf_share_method_type = BUF_SHARE_METHOD_TIZEN_BUFFER; + GST_WARNING_OBJECT (fimcconvert, "InBuf :: buf_share_method_type = TIZEN_BUFFER"); +#else + fimcconvert->buf_share_method_type = BUF_SHARE_METHOD_FD; + GST_WARNING_OBJECT (fimcconvert, "InBuf :: buf_share_method_type = FD"); +#endif + } else { + fimcconvert->buf_share_method_type = BUF_SHARE_METHOD_PADDR; + GST_WARNING_OBJECT (fimcconvert, "InBuf :: buf_share_method_type = PADDR"); + } + } + + fimcconvert->gem_info_src[src_idx][SCMN_Y_PLANE].gem_handle = fimcconvert->gem_info_src_normal_fmt[src_idx].gem_handle; + GST_DEBUG_OBJECT (fimcconvert, "InBuf :: gem_info_src[%d].gem_handle_y=%u", src_idx, fimcconvert->gem_info_src[src_idx][SCMN_Y_PLANE].gem_handle); + } + + GST_DEBUG_OBJECT (fimcconvert, "[END]"); +#ifdef DEBUG_FOR_DV + if (total_converted_frame_count <= 10) { + GST_WARNING_OBJECT (fimcconvert, "[END]"); + } +#endif + + return TRUE; +} + +static gboolean +gst_fimcconvert_drm_prepare_dst_buf(GstFimcConvert *fimcconvert) +{ + guint dst_idx = 0; + + g_return_val_if_fail (GST_IS_FIMCCONVERT (fimcconvert), FALSE); + + GST_DEBUG_OBJECT (fimcconvert, "[START]"); +#ifdef DEBUG_FOR_DV + if (total_converted_frame_count <= 10) { + GST_WARNING_OBJECT (fimcconvert, "[START]"); + } +#endif + + dst_idx = fimcconvert->dst_buf_idx; + + /* Make gem handle and do map for dst buffer */ + if (!gst_fimcconvert_tbm_create_and_map_bo(fimcconvert, FIMCCONVERT_GEM_FOR_DST)) { + return FALSE; + } + + if (fimcconvert->buf_share_method_type == BUF_SHARE_METHOD_PADDR) { + GST_LOG_OBJECT (fimcconvert, "OutBuf :: buf_share_method_type == PADDR"); + + /* Get phy address of each gem handle for destination */ + if (fimcconvert_drm_gem_get_phy_addr(fimcconvert->drm_fimc_fd, + fimcconvert->gem_info_dst[dst_idx][SCMN_Y_PLANE].gem_handle, &fimcconvert->gem_info_dst[dst_idx][SCMN_Y_PLANE].phy_addr)) { + return FALSE; + } + if (fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','N','1','2') + || fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','T','1','2')) { + /* CBCR Plane */ + if (fimcconvert_drm_gem_get_phy_addr(fimcconvert->drm_fimc_fd, + fimcconvert->gem_info_dst[dst_idx][SCMN_CB_PLANE].gem_handle, &fimcconvert->gem_info_dst[dst_idx][SCMN_CB_PLANE].phy_addr)) { + return FALSE; + } + /* Memset according to colorspace format (NV12) */ + if (fimcconvert->dst_format_drm == DRM_FORMAT_NV12) { + int y_size = fimcconvert->dst_caps_width * fimcconvert->dst_caps_height; + GST_LOG_OBJECT (fimcconvert, "memset : y_addr(0x%x), size(%d)", + (void*)(unsigned long)fimcconvert->gem_info_dst[dst_idx][SCMN_Y_PLANE].usr_addr, y_size); + if (fimcconvert->gem_info_dst[dst_idx][SCMN_Y_PLANE].usr_addr) { + memset ((void*)(unsigned long)fimcconvert->gem_info_dst[dst_idx][SCMN_Y_PLANE].usr_addr, 16, y_size); + } + if (fimcconvert->dst_format_drm == DRM_FORMAT_NV12) { + GST_LOG_OBJECT (fimcconvert, "memset : cbcr_addr(0x%x), size(%d)", + (void*)(unsigned long)fimcconvert->gem_info_dst[dst_idx][SCMN_CB_PLANE].usr_addr, fimcconvert->dst_buf_size - y_size); + if (fimcconvert->gem_info_dst[dst_idx][SCMN_CB_PLANE].usr_addr) { + memset ((void*)(unsigned long)fimcconvert->gem_info_dst[dst_idx][SCMN_CB_PLANE].usr_addr, 128, fimcconvert->dst_buf_size - y_size); + } + } + } + } else if (fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','4','2','0')) { + /* CB Plane */ + if (fimcconvert_drm_gem_get_phy_addr(fimcconvert->drm_fimc_fd, + fimcconvert->gem_info_dst[dst_idx][SCMN_CB_PLANE].gem_handle, &fimcconvert->gem_info_dst[dst_idx][SCMN_CB_PLANE].phy_addr)) { + return FALSE; + } + /* CR Plane */ + if (fimcconvert_drm_gem_get_phy_addr(fimcconvert->drm_fimc_fd, + fimcconvert->gem_info_dst[dst_idx][SCMN_CR_PLANE].gem_handle, &fimcconvert->gem_info_dst[dst_idx][SCMN_CR_PLANE].phy_addr)) { + return FALSE; + } + /* Memset according to colorspace format (YUV420) */ + { + int y_size = fimcconvert->dst_caps_width * fimcconvert->dst_caps_height; + GST_LOG_OBJECT (fimcconvert, "memset : y_addr(0x%x), size(%d)", + (void*)(unsigned long)fimcconvert->gem_info_dst[dst_idx][SCMN_Y_PLANE].usr_addr, y_size); + if (fimcconvert->gem_info_dst[dst_idx][SCMN_Y_PLANE].usr_addr) { + memset ((void*)(unsigned long)fimcconvert->gem_info_dst[dst_idx][SCMN_Y_PLANE].usr_addr, 16, y_size); + } + int cb_size = (fimcconvert->dst_caps_width * fimcconvert->dst_caps_height) >> 2; + GST_LOG_OBJECT (fimcconvert, "memset : cb_addr(0x%x), size(%d)", + (void*)(unsigned long)fimcconvert->gem_info_dst[dst_idx][SCMN_CB_PLANE].usr_addr, cb_size); + if (fimcconvert->gem_info_dst[dst_idx][SCMN_CB_PLANE].usr_addr) { + memset ((void*)(unsigned long)fimcconvert->gem_info_dst[dst_idx][SCMN_CB_PLANE].usr_addr, 128, cb_size); + } + GST_LOG_OBJECT (fimcconvert, "memset : cr_addr(0x%x), size(%d)", + (void*)(unsigned long)fimcconvert->gem_info_dst[dst_idx][SCMN_CR_PLANE].usr_addr, cb_size); + if (fimcconvert->gem_info_dst[dst_idx][SCMN_CR_PLANE].usr_addr) { + memset ((void*)(unsigned long)fimcconvert->gem_info_dst[dst_idx][SCMN_CR_PLANE].usr_addr, 128, cb_size); + } + } + } + } else if (fimcconvert->buf_share_method_type == BUF_SHARE_METHOD_FD || fimcconvert->buf_share_method_type == BUF_SHARE_METHOD_TIZEN_BUFFER ) { + GST_LOG_OBJECT (fimcconvert, "OutBuf :: buf_share_method_type (%d)", fimcconvert->buf_share_method_type); + + } + + GST_DEBUG_OBJECT (fimcconvert, "[END]"); +#ifdef DEBUG_FOR_DV + if (total_converted_frame_count <= 10) { + GST_WARNING_OBJECT (fimcconvert, "[END]"); + } +#endif + + return TRUE; +} + +static void +gst_fimcconvert_tbm_unmap_and_destroy_bo(GstFimcConvert *fimcconvert, FimcConvertGemCreateType type, int index) +{ + int i = 0; + int tbm_ret = 0; + if (type == FIMCCONVERT_GEM_FOR_SRC) { + /* for standard colorspace format */ + if (fimcconvert->gem_info_src_normal_fmt[index].bo) { + GST_LOG_OBJECT (fimcconvert, "SRC : (standard format) unmap src(%p)", (void*)(unsigned long)fimcconvert->gem_info_src_normal_fmt[index].usr_addr); + tbm_ret = tbm_bo_unmap(fimcconvert->gem_info_src_normal_fmt[index].bo); + if (tbm_ret == 0) { + GST_ERROR_OBJECT (fimcconvert, "SRC : (standard format) failed to tbm_bo_unmap(bo:%p), index(%d)", fimcconvert->gem_info_src_normal_fmt[index].bo, index); + } + GST_LOG_OBJECT (fimcconvert, "SRC : (standard format) tbm_bo_unref(bo:%p), index(%d)", fimcconvert->gem_info_src_normal_fmt[index].bo, index); + tbm_bo_unref (fimcconvert->gem_info_src_normal_fmt[index].bo); + memset(&fimcconvert->gem_info_src_normal_fmt[index], 0x00, sizeof(GemInfoDst)); + } + /* for samsung extension colorspace format */ + for (i = 0; i < SCMN_IMGB_MAX_PLANE-1; i++) { + if (fimcconvert->gem_info_src[index][i].bo) { + memset(&fimcconvert->gem_info_src[index], 0x00, sizeof(GemInfoSrc)); + } + if (fimcconvert->gem_info_src[index][i].dma_buf_fd || fimcconvert->gem_info_src[index][i].phy_addr) { + GST_LOG_OBJECT (fimcconvert, "SRC : close gem_handle(%d)", fimcconvert->gem_info_src[index][i].gem_handle); + fimcconvert_drm_close_gem(fimcconvert->drm_fimc_fd, fimcconvert->gem_info_src[index][i].gem_handle); + memset(&fimcconvert->gem_info_src[index], 0x00, sizeof(GemInfoSrc)); + } + } + } else if (type == FIMCCONVERT_GEM_FOR_DST) { + for (i = 0; i < SCMN_IMGB_MAX_PLANE-1; i++) { + if (fimcconvert->gem_info_dst[index][i].bo) { + GST_LOG_OBJECT (fimcconvert, "DST : unref dst(%p)", (void*)(unsigned long)fimcconvert->gem_info_dst[index][i].usr_addr); + tbm_bo_unref (fimcconvert->gem_info_dst[index][i].bo); + } + if (fimcconvert->gem_info_dst[index][i].dma_buf_fd) { + GST_LOG_OBJECT (fimcconvert, "DST : close fd(%d)", fimcconvert->gem_info_dst[index][i].dma_buf_fd); + close(fimcconvert->gem_info_dst[index][i].dma_buf_fd); + } + memset(&fimcconvert->gem_info_dst[index][i], 0x00, sizeof(GemInfoDst)); + } + } + + return; +} + +static gboolean +gst_fimcconvert_tbm_create_and_map_bo(GstFimcConvert *fimcconvert, FimcConvertGemCreateType type) +{ + tbm_bo bo; + tbm_bo_handle bo_handle_vaddr; + tbm_bo_handle bo_handle_gem; + guint src_idx = 0; + guint dst_idx = 0; + gint mem_option = 0; + + g_return_val_if_fail (GST_IS_FIMCCONVERT (fimcconvert), FALSE); + g_return_val_if_fail (fimcconvert->drm_fimc_fd, -1); + g_return_val_if_fail (fimcconvert->dst_buf_size, -1); + + src_idx = fimcconvert->src_buf_idx; + dst_idx = fimcconvert->dst_buf_idx; + + if (fimcconvert->buf_share_method_type == BUF_SHARE_METHOD_PADDR) { + mem_option = MEM_OP_NONCACHE_CONTIG; + } else { + mem_option = MEM_OP_NONCACHE_NONCONTIG; + } + GST_WARNING_OBJECT (fimcconvert, "memory option=%d (2:NONCACHEABLE_NONCONTIG 3:NONCACHEABLE_CONTIG)", mem_option); + + if (type == FIMCCONVERT_GEM_FOR_SRC) { + + GST_DEBUG_OBJECT (fimcconvert, "create and map bo for SRC"); + + g_return_val_if_fail (fimcconvert->src_buf_size, -1); + + /* allocate and map memory */ + FIMCCONVERT_TBM_BO_ALLOC_AND_MAP(bo, bo_handle_vaddr, fimcconvert->src_buf_size, mem_option); + + /* get gem handle */ + FIMCCONVERT_TBM_BO_GET_GEM_HANDLE(bo, bo_handle_gem); + + /* update information */ + fimcconvert->gem_info_src_normal_fmt[src_idx].gem_handle = bo_handle_gem.u32; + fimcconvert->gem_info_src_normal_fmt[src_idx].usr_addr = bo_handle_vaddr.ptr; + fimcconvert->gem_info_src_normal_fmt[src_idx].size = fimcconvert->src_buf_size; + fimcconvert->gem_info_src_normal_fmt[src_idx].bo = bo; + GST_DEBUG_OBJECT (fimcconvert, "gem_handle=%u, user addr=%p, size=%u", bo_handle_gem.u32, bo_handle_vaddr.ptr, fimcconvert->src_buf_size); + + } else if (type == FIMCCONVERT_GEM_FOR_DST) { + + GST_DEBUG_OBJECT (fimcconvert, "create and map bo for DST"); + + g_return_val_if_fail (fimcconvert->dst_buf_size, -1); + g_return_val_if_fail (fimcconvert->dst_caps_width, -1); + g_return_val_if_fail (fimcconvert->dst_caps_height, -1); + + int y_size = 0; + int cb_size = 0; + int cr_size = 0; + + /* for Y plane */ + /* initialize structure for gem create */ + if (fimcconvert->dst_format_drm == DRM_FORMAT_NV12MT) { + GST_DEBUG_OBJECT (fimcconvert, "It's ST12, set Y plane"); + y_size = ALIGN_TO_8KB( ALIGN_TO_128B(fimcconvert->dst_caps_width) * ALIGN_TO_32B(fimcconvert->dst_caps_height)); + } else if (fimcconvert->dst_format_drm == DRM_FORMAT_NV12 || + fimcconvert->dst_format_drm == DRM_FORMAT_YUV420) { + if (fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','N','1','2')) { + y_size = ALIGN_TO_16B(fimcconvert->dst_caps_width) * ALIGN_TO_16B(fimcconvert->dst_caps_height); + } else if (fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','4','2','0')) { + if (fimcconvert->buf_share_method_type == BUF_SHARE_METHOD_PADDR) { + y_size = ALIGN_TO_16B(fimcconvert->dst_caps_width) * ALIGN_TO_2B(fimcconvert->dst_caps_height); + } else { + y_size = (ALIGN_TO_16B(fimcconvert->dst_caps_width) * ALIGN_TO_2B(fimcconvert->dst_caps_height) * 3) >> 1; + } + } else { + y_size = fimcconvert->dst_buf_size; + } + } else { + if (fimcconvert->dst_format_drm == DRM_FORMAT_YUYV || + fimcconvert->dst_format_drm == DRM_FORMAT_UYVY ) { + y_size = (ALIGN_TO_16B(fimcconvert->dst_caps_width) * ALIGN_TO_2B(fimcconvert->dst_caps_height) * 2); + } else { + /* maybe, it's rgb case */ + y_size = fimcconvert->dst_buf_size; + } + } + + /* allocate and map memory */ + FIMCCONVERT_TBM_BO_ALLOC(bo, y_size, mem_option); + FIMCCONVERT_TBM_BO_GET_VADDR(bo, bo_handle_vaddr, y_size); + + /* get gem handle */ + FIMCCONVERT_TBM_BO_GET_GEM_HANDLE(bo, bo_handle_gem); + + /* update information */ + fimcconvert->gem_info_dst[dst_idx][SCMN_Y_PLANE].gem_handle = bo_handle_gem.u32; + fimcconvert->gem_info_dst[dst_idx][SCMN_Y_PLANE].usr_addr = bo_handle_vaddr.ptr; + fimcconvert->gem_info_dst[dst_idx][SCMN_Y_PLANE].size = y_size; + fimcconvert->gem_info_dst[dst_idx][SCMN_Y_PLANE].bo = bo; + + if (fimcconvert->buf_share_method_type == BUF_SHARE_METHOD_FD) { + if (fimcconvert_drm_convert_gemhandle_to_fd(fimcconvert->drm_fimc_fd, fimcconvert->gem_info_dst[dst_idx][SCMN_Y_PLANE].gem_handle, &fimcconvert->gem_info_dst[dst_idx][SCMN_Y_PLANE].dma_buf_fd)) { + return FALSE; + } + } + GST_DEBUG_OBJECT (fimcconvert, "Y: gem_handle=%u, user addr=%p, size=%u", bo_handle_gem.u32, bo_handle_vaddr.ptr, y_size); + + if (fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','N','1','2') + || fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','T','1','2') + || ((fimcconvert->buf_share_method_type == BUF_SHARE_METHOD_PADDR) && fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','4','2','0'))) { + + /* for CB(CR) plane */ + /* initialize structure for gem create */ + if (fimcconvert->dst_format_drm == DRM_FORMAT_NV12MT) { + /* for cbcr plane */ + GST_DEBUG_OBJECT (fimcconvert, "It's ST12, set CBCR plane"); + cb_size = ALIGN_TO_8KB( ALIGN_TO_128B(fimcconvert->dst_caps_width) * ALIGN_TO_32B(fimcconvert->dst_caps_height>>1) ); + } else if (fimcconvert->dst_format_drm == DRM_FORMAT_NV12) { + /* for cbcr plane */ + cb_size = y_size >> 1; + } else if (fimcconvert->dst_format_drm == DRM_FORMAT_YUV420) { + cb_size = y_size >> 2; + } + + /* allocate and map memory */ + FIMCCONVERT_TBM_BO_ALLOC(bo, cb_size, mem_option); + FIMCCONVERT_TBM_BO_GET_VADDR(bo, bo_handle_vaddr, cb_size); + + /* get gem handle */ + FIMCCONVERT_TBM_BO_GET_GEM_HANDLE(bo, bo_handle_gem); + + /* update information */ + fimcconvert->gem_info_dst[dst_idx][SCMN_CB_PLANE].gem_handle = bo_handle_gem.u32; + fimcconvert->gem_info_dst[dst_idx][SCMN_CB_PLANE].usr_addr = bo_handle_vaddr.ptr; + fimcconvert->gem_info_dst[dst_idx][SCMN_CB_PLANE].size = cb_size; + fimcconvert->gem_info_dst[dst_idx][SCMN_CB_PLANE].bo = bo; + + if (fimcconvert->buf_share_method_type == BUF_SHARE_METHOD_FD) { + if (fimcconvert_drm_convert_gemhandle_to_fd(fimcconvert->drm_fimc_fd, fimcconvert->gem_info_dst[dst_idx][SCMN_CB_PLANE].gem_handle, &fimcconvert->gem_info_dst[dst_idx][SCMN_CB_PLANE].dma_buf_fd)) { + return FALSE; + } + } + GST_DEBUG_OBJECT (fimcconvert, "CB(CR): gem_handle=%u, user addr=%p, size=%u", bo_handle_gem.u32, bo_handle_vaddr.ptr, cb_size); + + /* for CR plane */ + if (fimcconvert->dst_format_drm == DRM_FORMAT_YUV420) { + cr_size = cb_size; + + /* allocate and map memory */ + FIMCCONVERT_TBM_BO_ALLOC(bo, cr_size, mem_option); + FIMCCONVERT_TBM_BO_GET_VADDR(bo, bo_handle_vaddr, cr_size); + + /* get gem handle */ + FIMCCONVERT_TBM_BO_GET_GEM_HANDLE(bo, bo_handle_gem); + + /* update information */ + fimcconvert->gem_info_dst[dst_idx][SCMN_CR_PLANE].gem_handle = bo_handle_gem.u32; + fimcconvert->gem_info_dst[dst_idx][SCMN_CR_PLANE].usr_addr = bo_handle_vaddr.ptr; + fimcconvert->gem_info_dst[dst_idx][SCMN_CR_PLANE].size = cr_size; + fimcconvert->gem_info_dst[dst_idx][SCMN_CR_PLANE].bo = bo; + + if (fimcconvert->buf_share_method_type == BUF_SHARE_METHOD_FD) { + if (fimcconvert_drm_convert_gemhandle_to_fd(fimcconvert->drm_fimc_fd, fimcconvert->gem_info_dst[dst_idx][SCMN_CR_PLANE].gem_handle, &fimcconvert->gem_info_dst[dst_idx][SCMN_CR_PLANE].dma_buf_fd)) { + return FALSE; + } + } + GST_DEBUG_OBJECT (fimcconvert, "CR: gem_handle=%u, user addr=%p, size=%u", bo_handle_gem.u32, bo_handle_vaddr.ptr, cr_size); + } + } + } else { + GST_ERROR ("invalid type(%d) for gem creation", type); + return FALSE; + } + + return TRUE; +} + +int +util_write_rawdata(const char *file, const void *data, unsigned int size) +{ + FILE *fp; + + fp = fopen(file, "wb"); + if (fp == NULL) + return -1; + + fwrite((char*)data, sizeof(char), size, fp); + fclose(fp); + + return 0; +} + +static GstFlowReturn +gst_fimcconvert_transform(GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer *outbuf) +{ + int ret = 0; + int gret = TRUE; + + GstFimcConvert *fimcconvert = NULL; + SCMN_IMGB *imgb = NULL; + GstMemory *imgb_memory = NULL; + GstMapInfo imgb_info = GST_MAP_INFO_INIT; + guint src_idx = 0; + guint dst_idx = 0; + + struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; + fd_set fds; + + fimcconvert = GST_FIMCCONVERT(trans); + + GST_DEBUG_OBJECT (fimcconvert, "[START]"); + + /* check if all destination buffers are full */ + if (!gst_fimcconvert_is_buffer_available(fimcconvert)) { + GST_DEBUG_OBJECT (fimcconvert, "[END]"); + return GST_FLOW_ERROR; + } + + /* Set src/dst index */ + src_idx = fimcconvert->src_buf_idx; + dst_idx = fimcconvert->dst_buf_idx; + + g_mutex_lock (fimcconvert->fd_lock); + g_mutex_lock (instance_lock); + +#ifdef DEBUG_FOR_DV + if (total_converted_frame_count <= 10) { + GST_WARNING_OBJECT (fimcconvert, "is_src_format_std(%d), inbuf(%p)",fimcconvert->is_src_format_std,inbuf); + } +#endif + if (!fimcconvert->is_src_format_std) { + /* get an imgb of input buffer */ + if (gst_buffer_n_memory(inbuf) <= 2) { + GST_WARNING_OBJECT (fimcconvert, "failed to get SCMN_IMGB"); + goto SKIP_CONVERTING; + } else { +#ifdef USE_DETECT_JPEG + /* detect JPEG data */ + imgb_memory = gst_buffer_peek_memory(inbuf, 1); + gst_memory_map(imgb_memory, &imgb_info, GST_MAP_READ); + imgb = (SCMN_IMGB *)imgb_info.data; + gst_memory_unmap(imgb_memory, &imgb_info); + if (imgb->jpeg_data && imgb->jpeg_size) { + GST_LOG_OBJECT (fimcconvert, "got a JPEG data"); + fimcconvert->jpeg_data = imgb->jpeg_data; + fimcconvert->jpeg_data_size = imgb->jpeg_size; + } else { + fimcconvert->jpeg_data = NULL; + fimcconvert->jpeg_data_size = 0; + } +#endif + } + } + + /* initializing DRM IPP */ + if (!fimcconvert->is_drm_inited) { + if (!fimcconvert->is_src_format_std && imgb->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER && imgb->drm_fd) { + fimcconvert->drm_tbm_fd = imgb->drm_fd; + GST_WARNING_OBJECT (fimcconvert, "drm fd for tbm : %d", fimcconvert->drm_tbm_fd); + } + /* Open DRM */ + if (!gst_fimcconvert_drm_ipp_init(fimcconvert)) { + GST_ERROR_OBJECT (fimcconvert, "failed to gst_fimcconvert_drm_ipp_init()"); + g_mutex_unlock (instance_lock); + g_mutex_unlock (fimcconvert->fd_lock); + return GST_FLOW_ERROR; + } + } + + /* Do below only when first round */ + if (fimcconvert->is_random_src_idx) { + GST_DEBUG_OBJECT (fimcconvert, "===== Set for SRC =================================================================="); + if (fimcconvert->is_src_format_std) { + /* if src colorspace format is standard format, do below just once. */ + if (!fimcconvert->gem_info_src_normal_fmt[0].gem_handle) { + gret = gst_fimcconvert_drm_prepare_src_buf(fimcconvert, inbuf); + if (!gret) { + if (!fimcconvert->do_skip) { + goto ERROR; + } + } + } + } else { + gret = gst_fimcconvert_drm_prepare_src_buf(fimcconvert, inbuf); + if (!gret) { + if (!fimcconvert->do_skip) { + goto ERROR; + } + } + } + GST_DEBUG_OBJECT (fimcconvert, "==================================================================================="); + } else if (fimcconvert->is_first_set_for_src) { + /* Check if src buffer from decoder has new phy address */ + if (gst_fimcconvert_check_new_src(fimcconvert, inbuf)) { + GST_DEBUG_OBJECT (fimcconvert, "===== First Set for SRC : Round %d =================================================",src_idx+1); + gret = gst_fimcconvert_drm_prepare_src_buf(fimcconvert, inbuf); + if (!gret) { + if (!fimcconvert->do_skip) { + goto ERROR; + } + } + GST_DEBUG_OBJECT (fimcconvert, "==================================================================================="); + } else { + /* check if this buffer should be skipped */ + if (fimcconvert->do_skip) { + GST_WARNING_OBJECT (fimcconvert, "something wrong, gem_handle_y is 0. maybe this src buffer has invalid paddr/fd"); + /* set is_random_src_idx to TRUE and reset all buffers */ + fimcconvert->is_random_src_idx = TRUE; + g_mutex_unlock (instance_lock); + g_mutex_unlock (fimcconvert->fd_lock); + gst_fimcconvert_reset(fimcconvert); + g_mutex_lock (fimcconvert->fd_lock); + g_mutex_lock (instance_lock); + } else { + GST_INFO_OBJECT (fimcconvert, "found number of decoder output buffer(%d)",src_idx); + fimcconvert->src_buf_num = src_idx; + fimcconvert->is_first_set_for_src = FALSE; + fimcconvert->src_buf_idx = src_idx = 0; + } + } + } + + /* check if this buffer should be skipped */ + if (fimcconvert->do_skip) { + goto SKIP_CONVERTING; + } + + if (fimcconvert->is_first_set_for_dst) { + GST_DEBUG_OBJECT (fimcconvert, "===== First Set for DST : Round %d =================================================",dst_idx+1); + gret = gst_fimcconvert_drm_prepare_dst_buf(fimcconvert); + if (!gret) { + goto ERROR; + } + GST_DEBUG_OBJECT (fimcconvert, "==================================================================================="); + } + + /* Check if src data's colorspace is normal format */ + if (fimcconvert->is_src_format_std) { + GST_INFO_OBJECT (fimcconvert, "InBuf :: It's a standard format(%d), Do memory copy",fimcconvert->src_format_drm); + gst_buffer_extract(inbuf, 0, (void*)(unsigned int)fimcconvert->gem_info_src_normal_fmt[src_idx].usr_addr, gst_buffer_get_size(inbuf)); +#ifdef USE_CACHABLE_GEM + fimcconvert_gem_flush_cache(fimcconvert->drm_fimc_fd); +#endif +#ifdef DUMP_IMG + int ret = 0; + GST_INFO ("DUMP SRC IMG : inbuf size(%d)", GST_BUFFER_SIZE(inbuf)); + ret = util_write_rawdata("dump_raw_src_img", GST_BUFFER_DATA(inbuf), GST_BUFFER_SIZE(inbuf)); + if (ret) { + GST_ERROR_OBJECT (fimcconvert, "util_write_rawdata() failed"); + } +#endif + } + + /* Enqueue src buffer */ + GST_LOG_OBJECT (fimcconvert, "enqueue src buffer : src_idx(%d), gem_handle_y(%u), gem_handle_cb(%u), gem_handle_cr(%u)", + src_idx,fimcconvert->gem_info_src[src_idx][SCMN_Y_PLANE].gem_handle,fimcconvert->gem_info_src[src_idx][SCMN_CB_PLANE].gem_handle,fimcconvert->gem_info_src[src_idx][SCMN_CR_PLANE].gem_handle); + ret = exynos_drm_ipp_queue_buf(fimcconvert->drm_fimc_fd, EXYNOS_DRM_OPS_SRC, IPP_BUF_ENQUEUE, fimcconvert->ipp_prop_id, src_idx, + fimcconvert->gem_info_src[src_idx][SCMN_Y_PLANE].gem_handle, fimcconvert->gem_info_src[src_idx][SCMN_CB_PLANE].gem_handle, + fimcconvert->gem_info_src[src_idx][SCMN_CR_PLANE].gem_handle); + if (ret) { + GST_ERROR_OBJECT (fimcconvert, "src buffer map to IPP failed, src_buf_idx(%d)", src_idx); + goto ERROR; + } + + /* Enqueue dst buffer */ + GST_LOG_OBJECT (fimcconvert, "enqueue dst buffer : dst_idx(%d), gem_handle_y(%u), gem_handle_cb(%u), gem_handle_cr(%u)", + dst_idx, fimcconvert->gem_info_dst[dst_idx][SCMN_Y_PLANE].gem_handle, fimcconvert->gem_info_dst[dst_idx][SCMN_CB_PLANE].gem_handle, fimcconvert->gem_info_dst[dst_idx][SCMN_CR_PLANE].gem_handle); + ret = exynos_drm_ipp_queue_buf(fimcconvert->drm_fimc_fd, EXYNOS_DRM_OPS_DST, IPP_BUF_ENQUEUE, fimcconvert->ipp_prop_id, dst_idx, + fimcconvert->gem_info_dst[dst_idx][SCMN_Y_PLANE].gem_handle, fimcconvert->gem_info_dst[dst_idx][SCMN_CB_PLANE].gem_handle, fimcconvert->gem_info_dst[dst_idx][SCMN_CR_PLANE].gem_handle); + if (ret) { + GST_ERROR_OBJECT (fimcconvert, "dst buffer map to IPP failed, dst_buf_idx(%d)", dst_idx); + goto ERROR; + } + + /* Set IPP to start */ + if (!fimcconvert->is_drm_inited) { + if (!gst_fimcconvert_drm_ipp_ctrl(fimcconvert, FIMCCONVERT_IPP_CTRL_START)) { + GST_ERROR_OBJECT (fimcconvert, "failed to gst_fimcconvert_drm_ipp_ctrl(START)"); + goto ERROR; + } + } + + /* Wait using select */ + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(fimcconvert->drm_fimc_fd, &fds); + ret = select(fimcconvert->drm_fimc_fd + 1, &fds, NULL, NULL, &timeout); + if (ret == 0 ) { + GST_ERROR_OBJECT (fimcconvert, "select timed out.."); + goto ERROR; + } + if (ret == -1) { + GST_ERROR_OBJECT (fimcconvert, "select error, error num(%d)",errno); + goto ERROR; + } + + /* Event handling */ + { + char buffer[MAX_IPP_EVENT_BUFFER_SIZE] = {0}; + int len = 0; + int i = 0; + struct drm_event *e; + struct drm_exynos_ipp_event *ipp_event; + +#ifdef DEBUG_FOR_DV + if (total_converted_frame_count <= 10) { + GST_WARNING_OBJECT (fimcconvert, "before reading IPP event (no.%d)", total_converted_frame_count+1); + } +#endif + + len = read(fimcconvert->drm_fimc_fd, buffer, MAX_IPP_EVENT_BUFFER_SIZE-1); + if (len == 0 || len < sizeof *e) { + GST_ERROR_OBJECT (fimcconvert, "lengh(%d) is not valid", len); + goto ERROR; + } + + while (i < len) { + e = (struct drm_event *) &buffer[i]; + switch (e->type) { + case DRM_EXYNOS_IPP_EVENT: + ipp_event = (struct drm_exynos_ipp_event *) e; + src_idx = ipp_event->buf_id[EXYNOS_DRM_OPS_SRC]; + dst_idx = ipp_event->buf_id[EXYNOS_DRM_OPS_DST]; + GST_LOG_OBJECT (fimcconvert, "got DRM_EXYNOS_IPP_EVENT : src_buf_idx(%d), dst_buf_idx(%d)",src_idx,dst_idx); + break; + default: + GST_WARNING_OBJECT (fimcconvert, "got DRM_EXYNOS Other EVENT(%d)",e->type); + break; + } + i += e->length; + } + +#ifdef DEBUG_FOR_DV + if (total_converted_frame_count <= 10) { + GST_WARNING_OBJECT (fimcconvert, "after reading IPP event (no.%d), got DRM_EXYNOS_IPP_EVENT : src_buf_idx(%d), dst_buf_idx(%d)", + total_converted_frame_count+1, src_idx, dst_idx); + } +#endif + } + + /* Update SCMN_IMGB information for outbuf */ + if ( fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','N','1','2') + || fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','T','1','2') + || fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','U','Y','V') + || fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','U','Y','2') + || fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','Y','V','Y') + || fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','4','2','0') + || fimcconvert->dst_format_gst == GST_MAKE_FOURCC('S','R','3','2') ) { + if (!gst_fimcconvert_set_imgb_info_for_dst(fimcconvert, outbuf)) { + GST_ERROR_OBJECT (fimcconvert, "set SCMN_IMGB information failed..idx(%d)",dst_idx); + goto ERROR; + } + } + + if (fimcconvert->is_random_src_idx) { + if (!fimcconvert->is_src_format_std) { + gst_fimcconvert_tbm_unmap_and_destroy_bo (fimcconvert, FIMCCONVERT_GEM_FOR_SRC, src_idx); + } + } else { + fimcconvert->src_buf_idx++; + if (fimcconvert->src_buf_idx == fimcconvert->src_buf_num || fimcconvert->src_buf_idx == MAX_SRC_BUF_NUM) { + if (fimcconvert->is_first_set_for_src) { + if (fimcconvert->src_buf_idx == MAX_SRC_BUF_NUM) { + } + GST_WARNING_OBJECT (fimcconvert, "it reached MAX_SRC_BUF_NUM(%d)", fimcconvert->src_buf_idx); + fimcconvert->is_first_set_for_src = FALSE; + } + fimcconvert->src_buf_idx = 0; + } + } + fimcconvert->dst_buf_idx++; + if (fimcconvert->dst_buf_idx == fimcconvert->num_of_dst_buffers) { + if (fimcconvert->is_first_set_for_dst) { + fimcconvert->is_first_set_for_dst = FALSE; + } + fimcconvert->dst_buf_idx = 0; + } + + { + GstFimcConvertBuffer* fimc_buf = NULL; + GstMemory *fimc_memory = gst_buffer_peek_memory(outbuf, gst_buffer_n_memory(outbuf) - 1); + GstMapInfo fimc_info = GST_MAP_INFO_INIT; + gst_memory_map(fimc_memory, &fimc_info, GST_MAP_READ); + fimc_buf = (GstFimcConvertBuffer*)fimc_info.data; + gst_memory_unmap(fimc_memory, &fimc_info); + gst_buffer_prepend_memory(outbuf, gst_memory_new_wrapped(GST_MEMORY_FLAG_READONLY, + (void*)(unsigned long)fimcconvert->gem_info_dst[dst_idx][SCMN_Y_PLANE].usr_addr, + fimc_buf->actual_size, + 0, + fimc_buf->actual_size, + NULL, + NULL)); + } + +#ifdef DUMP_IMG + GST_INFO ("DUMP DST IMG : outbuf size(%d)", GST_BUFFER_SIZE(outbuf)); + ret = util_write_rawdata("dump_raw_dst_img", GST_BUFFER_DATA(outbuf), GST_BUFFER_SIZE(outbuf)); + if (ret) { + GST_ERROR_OBJECT (fimcconvert, "util_write_rawdata() failed"); + } +#endif + + if (!fimcconvert->is_drm_inited) { + fimcconvert->is_drm_inited = TRUE; + FIMCCONVERT_SEND_CUSTOM_EVENT_TO_SINK_WITH_DATA( 1 ); + } +#ifdef USE_CACHABLE_GEM + __ta__(" flush_cache() after IPP", + fimcconvert_gem_flush_cache(fimcconvert->drm_fimc_fd); + ); +#endif + g_mutex_unlock (instance_lock); + g_mutex_unlock (fimcconvert->fd_lock); + + GST_DEBUG_OBJECT (fimcconvert, "[END]"); + +#ifdef DEBUG_FOR_DV + if (++total_converted_frame_count <= 10) { + GST_WARNING_OBJECT (fimcconvert, "%2dth of IPP operation, buffer(%p)", total_converted_frame_count, outbuf); + } +#endif + + return GST_FLOW_OK; + +SKIP_CONVERTING: + /* skipping converting in case of incoming src buf's information is not valid */ + GST_WARNING_OBJECT (fimcconvert, "SKIPPING CONVERTING.."); + + fimcconvert->do_skip = FALSE; + + g_mutex_lock (fimcconvert->buf_idx_lock); + if (fimcconvert->dst_buf_num > 0) { + fimcconvert->dst_buf_num--; + } + g_mutex_unlock (fimcconvert->buf_idx_lock); + + g_mutex_unlock (instance_lock); + g_mutex_unlock (fimcconvert->fd_lock); + + GST_DEBUG_OBJECT (fimcconvert, "[END]"); + return GST_BASE_TRANSFORM_FLOW_DROPPED; + +ERROR: + g_mutex_unlock (instance_lock); + g_mutex_unlock (fimcconvert->fd_lock); + + gst_fimcconvert_reset(fimcconvert); + + GST_DEBUG_OBJECT (fimcconvert, "[END]"); + return GST_FLOW_ERROR; +} + +static gboolean +plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT(fimcconvert_debug, "fimcconvert", 0, "Fimc Converter"); + return gst_element_register(plugin, "fimcconvert", GST_RANK_NONE, GST_TYPE_FIMCCONVERT); +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + fimcconvert, + "Fimc Converter", + plugin_init, VERSION, "LGPL", "Samsung Electronics Co", "http://www.samsung.com") + diff --git a/fimcconvert/src/gstfimcconvert.h b/fimcconvert/src/gstfimcconvert.h new file mode 100755 index 0000000..9d16856 --- /dev/null +++ b/fimcconvert/src/gstfimcconvert.h @@ -0,0 +1,380 @@ +/* + * FimcConvert + * + * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Sangchul Lee + * + * 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_FIMC_CONVERT_H__ +#define __GST_FIMC_CONVERT_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fimc_drm_api.h" + +G_BEGIN_DECLS + +GST_DEBUG_CATEGORY_EXTERN (fimcconvert_debug); +#define GST_CAT_DEFAULT fimcconvert_debug + +#define GST_TYPE_FIMCCONVERT (gst_fimcconvert_get_type()) +#define GST_FIMCCONVERT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FIMCCONVERT,GstFimcConvert)) +#define GST_FIMCCONVERT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FIMCCONVERT,GstFimcConvertClass)) +#define GST_IS_FIMCCONVERT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FIMCCONVERT)) +#define GST_IS_FIMCCONVERT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FIMCCONVERT)) + +typedef struct _GstFimcConvert GstFimcConvert; +typedef struct _GstFimcConvertClass GstFimcConvertClass; +typedef struct _GstFimcConvertBuffer GstFimcConvertBuffer; +typedef struct _GemInfoSrc GemInfoSrc; +typedef struct _GemInfoDst GemInfoDst; + +typedef enum { + BUF_SHARE_METHOD_PADDR = 0, + BUF_SHARE_METHOD_FD, + BUF_SHARE_METHOD_TIZEN_BUFFER +} buf_share_method_t; + +/* macro for sending custom event ********************************************/ +#define FIMCCONVERT_SEND_CUSTOM_EVENT_TO_SINK_WITH_DATA( x_addr ) \ +do \ +{ \ + GstEvent *event = NULL; \ + GstStructure *st = NULL; \ + st = gst_structure_new ("GstStructureForCustomEvent", "data-addr", G_TYPE_UINT, x_addr, NULL); \ + if (!st) { \ + GST_WARNING_OBJECT(fimcconvert,"structure make failed"); \ + } \ + GST_DEBUG ("set data addr(%x) in GstStructure",x_addr); \ + event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, st); \ + if (!event) { \ + GST_WARNING_OBJECT(fimcconvert,"event make failed"); \ + } \ + if (GST_IS_PAD (fimcconvert->src_pad)) { \ + if (!gst_pad_push_event(fimcconvert->src_pad, event)) { \ + GST_DEBUG_OBJECT(fimcconvert, "sending event failed, but keep going.."); \ + } \ + } \ +}while(0) + +/* macro related to TBM ******************************************************/ +#define FIMCCONVERT_TBM_BO_ALLOC( x_bo, x_size, x_mem_option ) \ +do \ +{ \ + x_bo = tbm_bo_alloc (fimcconvert->tbm, x_size, x_mem_option); \ + if (!x_bo) { \ + GST_ERROR_OBJECT(fimcconvert,"failed to tbm_bo_alloc(), size(%d)", x_size); \ + return FALSE; \ + } \ +}while(0) + +#define FIMCCONVERT_TBM_BO_ALLOC_AND_MAP( x_bo, x_bo_handle, x_size, x_mem_option ) \ +do \ +{ \ + x_bo = tbm_bo_alloc (fimcconvert->tbm, x_size, x_mem_option); \ + if (!x_bo) { \ + GST_ERROR_OBJECT(fimcconvert,"failed to tbm_bo_alloc(), size(%d)", x_size); \ + return FALSE; \ + } \ + x_bo_handle = tbm_bo_map (x_bo, TBM_DEVICE_CPU, TBM_OPTION_READ | TBM_OPTION_WRITE); \ + if (!x_bo_handle.ptr) { \ + GST_ERROR_OBJECT(fimcconvert,"failed to tbm_bo_map(), bo(%p)", x_bo); \ + return FALSE; \ + } \ + memset (x_bo_handle.ptr, 0x0, x_size); \ +}while(0) + +#define FIMCCONVERT_TBM_BO_GET_GEM_HANDLE( x_bo, x_bo_handle ) \ +do \ +{ \ + x_bo_handle = tbm_bo_get_handle(x_bo, TBM_DEVICE_2D); \ + if (!x_bo_handle.u32) { \ + GST_ERROR_OBJECT(fimcconvert,"failed to tbm_bo_get_handle(GEM_HANDLE), bo(%p), gem_handle(%d)", x_bo, x_bo_handle.u32); \ + return FALSE; \ + } else { \ + GST_LOG_OBJECT(fimcconvert,"tbm_bo_get_handle(GEM_HANDLE) finished, bo(%p), gem_handle(%d)", x_bo, x_bo_handle.u32); \ + } \ +}while(0) + +#define FIMCCONVERT_TBM_BO_GET_VADDR( x_bo, x_bo_handle, x_size ) \ +do \ +{ \ + x_bo_handle = tbm_bo_get_handle(x_bo, TBM_DEVICE_CPU); \ + if (!x_bo_handle.ptr) { \ + GST_ERROR_OBJECT(fimcconvert,"failed to tbm_bo_get_handle(VADDR), bo(%p), vaddr(%p)", x_bo, x_bo_handle.ptr); \ + return FALSE; \ + } else { \ + memset (x_bo_handle.ptr, 0x0, x_size); \ + GST_LOG_OBJECT(fimcconvert,"tbm_bo_get_handle(VADDR) finished, bo(%p), vaddr(%p)", x_bo, x_bo_handle.ptr); \ + } \ +}while(0) + +/* color spaces **************************************************************/ +/* YUV planar type */ +#define SCMN_CS_YUV400 0 /* Y */ +#define SCMN_CS_YUV420 1 /* Y:U:V 4:2:0 */ +#define SCMN_CS_YUV422 2 /* Y:U:V 4:2:2 */ +#define SCMN_CS_YUV444 3 /* Y:U:V 4:4:4 */ +#define SCMN_CS_YV12 4 /* Y:V:U 4:2:0 */ +#define SCMN_CS_I420 SCMN_CS_YUV420 /* Y:U:V */ +#define SCMN_CS_IYUV SCMN_CS_YUV420 /* Y:U:V */ +#define SCMN_CS_YV16 5 /* Y:V:U 4:2:2 */ +#define SCMN_CS_NV12 6 +#define SCMN_CS_NV21 7 +#define SCMN_CS_YUV422N SCMN_CS_YUV422 +#define SCMN_CS_YUV422W 8 +#define SCMN_CS_GRAY SCMN_CS_YUV400 +#define SCMN_CS_Y800 SCMN_CS_YUV400 +#define SCMN_CS_Y16 9 +#define SCMN_CS_GRAYA 10 +#define SCMN_CS_NV12_T64X32 11 /* 64x32 Tiled NV12 type */ + +/* YUV pack type */ +#define SCMN_CS_UYVY 100 +#define SCMN_CS_YUYV 101 +#define SCMN_CS_YUY2 SCMN_CS_YUYV +#define SCMN_CS_V422 SCMN_CS_YUYV +#define SCMN_CS_YUNV SCMN_CS_YUYV +#define SCMN_CS_Y8A8 110 + +/* RGB pack type */ +#define SCMN_CS_RGB565 200 +#define SCMN_CS_BGR565 201 + +#define SCMN_CS_RGB555 210 /* 1 : R(5) : G(5) : R(5) */ +#define SCMN_CS_BGR555 211 + +#define SCMN_CS_RGB666 300 +#define SCMN_CS_BGR666 301 + +#define SCMN_CS_RGB888 400 +#define SCMN_CS_BGR888 401 + +#define SCMN_CS_RGBA8888 500 +#define SCMN_CS_BGRA8888 501 +#define SCMN_CS_ARGB8888 502 +#define SCMN_CS_ABGR8888 503 + +/* unknown color space */ +#define SCMN_CS_UNKNOWN 1000 + +/* macro for color space *****************************************************/ +#define SCMN_CS_IS_YUV(cs) ((cs)>=0 && (cs)<200) +#define SCMN_CS_IS_YUV_PLANAR(cs) ((cs)>=0 && (cs)<100) +#define SCMN_CS_IS_YUV_PACK(cs) ((cs)>=100 && (cs)<200) +#define SCMN_CS_IS_RGB_PACK(cs) ((cs)>=200 && (cs)<600) +#define SCMN_CS_IS_RGB16_PACK(cs) ((cs)>=200 && (cs)<300) +#define SCMN_CS_IS_RGB18_PACK(cs) ((cs)>=300 && (cs)<400) +#define SCMN_CS_IS_RGB24_PACK(cs) ((cs)>=400 && (cs)<500) +#define SCMN_CS_IS_RGB32_PACK(cs) ((cs)>=500 && (cs)<600) + +/* max channel count *********************************************************/ +#define SCMN_IMGB_MAX_PLANE (4) + +#define SCMN_Y_PLANE 0 +#define SCMN_CB_PLANE 1 +#define SCMN_CR_PLANE 2 + +/* image buffer definition *************************************************** + + +------------------------------------------+ --- + | | ^ + | a[], p[] | | + | +---------------------------+ --- | | + | | | ^ | | + | |<---------- w[] ---------->| | | | + | | | | | | + | | | | + | | | h[] | e[] + | | | | + | | | | | | + | | | | | | + | | | v | | + | +---------------------------+ --- | | + | | v + +------------------------------------------+ --- + + |<----------------- s[] ------------------>| +*/ + +typedef struct +{ + /* width of each image plane */ + int w[SCMN_IMGB_MAX_PLANE]; + /* height of each image plane */ + int h[SCMN_IMGB_MAX_PLANE]; + /* stride of each image plane */ + int s[SCMN_IMGB_MAX_PLANE]; + /* elevation of each image plane */ + int e[SCMN_IMGB_MAX_PLANE]; + /* user space address of each image plane */ + void * a[SCMN_IMGB_MAX_PLANE]; + /* physical address of each image plane, if needs */ + void * p[SCMN_IMGB_MAX_PLANE]; + /* color space type of image */ + int cs; + /* left postion, if needs */ + int x; + /* top position, if needs */ + int y; + /* to align memory */ + int __dummy2; + /* arbitrary data */ + int data[16]; + /* dma buf fd */ + int dma_buf_fd[SCMN_IMGB_MAX_PLANE]; + /* buffer share method */ + int buf_share_method; + /* Y plane size in case of ST12 */ + int y_size; + /* UV plane size in case of ST12 */ + int uv_size; + /* TBM buffer object */ + tbm_bo bo[SCMN_IMGB_MAX_PLANE]; + /* JPEG data */ + void *jpeg_data; + /* JPEG size */ + int jpeg_size; + /* DRM node fd for TBM */ + int drm_fd; +} SCMN_IMGB; + +#define FIMCCONVERT_DST_WIDTH_DEFAULT 0 +#define FIMCCONVERT_DST_WIDTH_MIN 0 +#define FIMCCONVERT_DST_WIDTH_MAX 32767 +#define FIMCCONVERT_DST_HEIGHT_DEFAULT 0 +#define FIMCCONVERT_DST_HEIGHT_MIN 0 +#define FIMCCONVERT_DST_HEIGHT_MAX 32767 +#define FIMCCONVERT_DST_BUFFER_MIN 2 +#define FIMCCONVERT_DST_BUFFER_DEFAULT 3 +#define FIMCCONVERT_DST_BUFFER_MAX 12 + +#define SRC_BUF_NUM_FOR_STD_FMT 6 /* fixed number of buffer for standard colorspace format */ +#define MAX_SRC_BUF_NUM 12 /* Max number of upstream src plugins's buffer */ +#define MAX_DST_BUF_NUM FIMCCONVERT_DST_BUFFER_MAX + +/* Dump raw img (src and dst) */ +//#define DUMP_IMG + +//#define USE_TBM +#define USE_DETECT_JPEG +#define MEM_OP_NONCACHE_NONCONTIG ( TBM_BO_DEFAULT | TBM_BO_NONCACHABLE ) +#define MEM_OP_NONCACHE_CONTIG ( TBM_BO_SCANOUT | TBM_BO_NONCACHABLE ) + +struct _GstFimcConvertBuffer { + GstBuffer *buffer; + GstFimcConvert *fimcconvert; + guint actual_size; +}; + +struct _GemInfoSrc { + unsigned int gem_handle; + uint64_t phy_addr; + int dma_buf_fd; + tbm_bo bo; + uint64_t size; +}; + +struct _GemInfoDst { + unsigned int gem_handle; + uint64_t usr_addr; + uint64_t phy_addr; + int dma_buf_fd; + tbm_bo bo; + uint64_t size; +}; + +struct _GstFimcConvert { + GstBaseTransform element; + GstPad* src_pad; + + /* Src paramters */ + gint src_caps_width; + gint src_caps_height; + guint src_buf_size; /**< for a standard colorspace format */ + guint32 src_format_drm; /**< fourcc colorspace format for src */ + gboolean is_src_format_std; + + /* Dst paramters */ + gint dst_caps_width; + gint dst_caps_height; + guint dst_buf_size; + guint32 dst_format_drm; /**< fourcc colorspace format for dst */ + guint32 dst_format_gst; /**< fourcc colorspace format of GST */ + + /* Properties */ + guint rotate_ang; + gint dst_width; + gint dst_height; + gint dst_flip; + gboolean is_random_src_idx; + guint num_of_dst_buffers; + + /* DRM/GEM information */ + gint drm_fimc_fd; + guint32 ipp_prop_id; + GemInfoSrc gem_info_src[MAX_SRC_BUF_NUM][SCMN_IMGB_MAX_PLANE]; + GemInfoDst gem_info_src_normal_fmt[MAX_SRC_BUF_NUM]; + GemInfoDst gem_info_dst[MAX_DST_BUF_NUM][SCMN_IMGB_MAX_PLANE]; + buf_share_method_t buf_share_method_type; + + /* Tizen Buffer Manager */ + tbm_bufmgr tbm; + gint drm_tbm_fd; + + gboolean do_skip; + gboolean is_same_caps; + gboolean is_drm_inited; + gboolean is_first_set_for_src; + gboolean is_first_set_for_dst; + guint src_buf_num; + guint src_buf_idx; + guint dst_buf_num; + guint dst_buf_idx; + + /* JPEG data */ + void *jpeg_data; + int jpeg_data_size; + + GMutex *fd_lock; + GMutex *buf_idx_lock; +}; + +struct _GstFimcConvertClass { + GstBaseTransformClass parent_class; +}; + +GType gst_fimcconvert_get_type(void); + +G_END_DECLS + +#endif /* __GST_FIMC_CONVERT_H__ */ + + diff --git a/gst-autogen.sh b/gst-autogen.sh new file mode 100755 index 0000000..7b31212 --- /dev/null +++ b/gst-autogen.sh @@ -0,0 +1,308 @@ +# a silly hack that generates autoregen.sh but it's handy +# Remove the old autoregen.sh first to create a new file, +# as the current one may be being read by the shell executing +# this script. +if [ -f "autoregen.sh" ]; then + rm autoregen.sh +fi +echo "#!/bin/sh" > autoregen.sh +echo "./autogen.sh $@ \$@" >> autoregen.sh +chmod +x autoregen.sh + +# helper functions for autogen.sh + +debug () +# print out a debug message if DEBUG is a defined variable +{ + if test ! -z "$DEBUG" + then + echo "DEBUG: $1" + fi +} + +version_check () +# check the version of a package +# first argument : package name (executable) +# second argument : optional path where to look for it instead +# third argument : source download url +# rest of arguments : major, minor, micro version +# all consecutive ones : suggestions for binaries to use +# (if not specified in second argument) +{ + PACKAGE=$1 + PKG_PATH=$2 + URL=$3 + MAJOR=$4 + MINOR=$5 + MICRO=$6 + + # for backwards compatibility, we let PKG_PATH=PACKAGE when PKG_PATH null + if test -z "$PKG_PATH"; then PKG_PATH=$PACKAGE; fi + debug "major $MAJOR minor $MINOR micro $MICRO" + VERSION=$MAJOR + if test ! -z "$MINOR"; then VERSION=$VERSION.$MINOR; else MINOR=0; fi + if test ! -z "$MICRO"; then VERSION=$VERSION.$MICRO; else MICRO=0; fi + + debug "major $MAJOR minor $MINOR micro $MICRO" + + for SUGGESTION in $PKG_PATH; do + COMMAND="$SUGGESTION" + + # don't check if asked not to + test -z "$NOCHECK" && { + echo -n " checking for $COMMAND >= $VERSION ... " + } || { + # we set a var with the same name as the package, but stripped of + # unwanted chars + VAR=`echo $PACKAGE | sed 's/-//g'` + debug "setting $VAR" + eval $VAR="$COMMAND" + return 0 + } + + debug "checking version with $COMMAND" + ($COMMAND --version) < /dev/null > /dev/null 2>&1 || + { + echo "not found." + continue + } + # strip everything that's not a digit, then use cut to get the first field + pkg_version=`$COMMAND --version|head -n 1|sed 's/^.*)[^0-9]*//'|cut -d' ' -f1` + debug "pkg_version $pkg_version" + # remove any non-digit characters from the version numbers to permit numeric + # comparison + pkg_major=`echo $pkg_version | cut -d. -f1 | sed s/[a-zA-Z\-].*//g` + pkg_minor=`echo $pkg_version | cut -d. -f2 | sed s/[a-zA-Z\-].*//g` + pkg_micro=`echo $pkg_version | cut -d. -f3 | sed s/[a-zA-Z\-].*//g` + test -z "$pkg_major" && pkg_major=0 + test -z "$pkg_minor" && pkg_minor=0 + test -z "$pkg_micro" && pkg_micro=0 + debug "found major $pkg_major minor $pkg_minor micro $pkg_micro" + + #start checking the version + debug "version check" + + # reset check + WRONG= + + if [ ! "$pkg_major" -gt "$MAJOR" ]; then + debug "major: $pkg_major <= $MAJOR" + if [ "$pkg_major" -lt "$MAJOR" ]; then + debug "major: $pkg_major < $MAJOR" + WRONG=1 + elif [ ! "$pkg_minor" -gt "$MINOR" ]; then + debug "minor: $pkg_minor <= $MINOR" + if [ "$pkg_minor" -lt "$MINOR" ]; then + debug "minor: $pkg_minor < $MINOR" + WRONG=1 + elif [ "$pkg_micro" -lt "$MICRO" ]; then + debug "micro: $pkg_micro < $MICRO" + WRONG=1 + fi + fi + fi + + if test ! -z "$WRONG"; then + echo "found $pkg_version, not ok !" + continue + else + echo "found $pkg_version, ok." + # we set a var with the same name as the package, but stripped of + # unwanted chars + VAR=`echo $PACKAGE | sed 's/-//g'` + debug "setting $VAR" + eval $VAR="$COMMAND" + return 0 + fi + done + + echo "not found !" + echo "You must have $PACKAGE installed to compile $package." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at $URL" + return 1; +} + +aclocal_check () +{ + # normally aclocal is part of automake + # so we expect it to be in the same place as automake + # so if a different automake is supplied, we need to adapt as well + # so how's about replacing automake with aclocal in the set var, + # and saving that in $aclocal ? + # note, this will fail if the actual automake isn't called automake* + # or if part of the path before it contains it + if [ -z "$automake" ]; then + echo "Error: no automake variable set !" + return 1 + else + aclocal=`echo $automake | sed s/automake/aclocal/` + debug "aclocal: $aclocal" + if [ "$aclocal" != "aclocal" ]; + then + CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-aclocal=$aclocal" + fi + if [ ! -x `which $aclocal` ]; then + echo "Error: cannot execute $aclocal !" + return 1 + fi + fi +} + +autoheader_check () +{ + # same here - autoheader is part of autoconf + # use the same voodoo + if [ -z "$autoconf" ]; then + echo "Error: no autoconf variable set !" + return 1 + else + autoheader=`echo $autoconf | sed s/autoconf/autoheader/` + debug "autoheader: $autoheader" + if [ "$autoheader" != "autoheader" ]; + then + CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-autoheader=$autoheader" + fi + if [ ! -x `which $autoheader` ]; then + echo "Error: cannot execute $autoheader !" + return 1 + fi + fi + +} +autoconf_2_52d_check () +{ + # autoconf 2.52d has a weird issue involving a yes:no error + # so don't allow it's use + test -z "$NOCHECK" && { + ac_version=`$autoconf --version|head -n 1|sed 's/^[a-zA-Z\.\ ()]*//;s/ .*$//'` + if test "$ac_version" = "2.52d"; then + echo "autoconf 2.52d has an issue with our current build." + echo "We don't know who's to blame however. So until we do, get a" + echo "regular version. RPM's of a working version are on the gstreamer site." + exit 1 + fi + } + return 0 +} + +die_check () +{ + # call with $DIE + # if set to 1, we need to print something helpful then die + DIE=$1 + if test "x$DIE" = "x1"; + then + echo + echo "- Please get the right tools before proceeding." + echo "- Alternatively, if you're sure we're wrong, run with --nocheck." + exit 1 + fi +} + +autogen_options () +{ + if test "x$1" = "x"; then + return 0 + fi + + while test "x$1" != "x" ; do + optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + case "$1" in + --noconfigure) + NOCONFIGURE=defined + AUTOGEN_EXT_OPT="$AUTOGEN_EXT_OPT --noconfigure" + echo "+ configure run disabled" + shift + ;; + --nocheck) + AUTOGEN_EXT_OPT="$AUTOGEN_EXT_OPT --nocheck" + NOCHECK=defined + echo "+ autotools version check disabled" + shift + ;; + --debug) + DEBUG=defined + AUTOGEN_EXT_OPT="$AUTOGEN_EXT_OPT --debug" + echo "+ debug output enabled" + shift + ;; + --prefix=*) + CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT --prefix=$optarg" + echo "+ passing --prefix=$optarg to configure" + shift + ;; + --prefix) + shift + echo "DEBUG: $1" + CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT --prefix=$1" + echo "+ passing --prefix=$1 to configure" + shift + ;; + + -h|--help) + echo "autogen.sh (autogen options) -- (configure options)" + echo "autogen.sh help options: " + echo " --noconfigure don't run the configure script" + echo " --nocheck don't do version checks" + echo " --debug debug the autogen process" + echo " --prefix will be passed on to configure" + echo + echo " --with-autoconf PATH use autoconf in PATH" + echo " --with-automake PATH use automake in PATH" + echo + echo "to pass options to configure, put them as arguments after -- " + exit 1 + ;; + --with-automake=*) + AUTOMAKE=$optarg + echo "+ using alternate automake in $optarg" + CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-automake=$AUTOMAKE" + shift + ;; + --with-autoconf=*) + AUTOCONF=$optarg + echo "+ using alternate autoconf in $optarg" + CONFIGURE_DEF_OPT="$CONFIGURE_DEF_OPT --with-autoconf=$AUTOCONF" + shift + ;; + --disable*|--enable*|--with*) + echo "+ passing option $1 to configure" + CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT $1" + shift + ;; + --) shift ; break ;; + *) echo "- ignoring unknown autogen.sh argument $1"; shift ;; + esac + done + + for arg do CONFIGURE_EXT_OPT="$CONFIGURE_EXT_OPT $arg"; done + if test ! -z "$CONFIGURE_EXT_OPT" + then + echo "+ options passed to configure: $CONFIGURE_EXT_OPT" + fi +} + +toplevel_check () +{ + srcfile=$1 + test -f $srcfile || { + echo "You must run this script in the top-level $package directory" + exit 1 + } +} + + +tool_run () +{ + tool=$1 + options=$2 + run_if_fail=$3 + echo "+ running $tool $options..." + $tool $options || { + echo + echo $tool failed + eval $run_if_fail + exit 1 + } +} diff --git a/gst-plugins-tizen1.0.manifest b/gst-plugins-tizen1.0.manifest new file mode 100644 index 0000000..a76fdba --- /dev/null +++ b/gst-plugins-tizen1.0.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/m4/Makefile.am b/m4/Makefile.am new file mode 100644 index 0000000..5fa63aa --- /dev/null +++ b/m4/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = as-version.m4 as-compiler-flag.m4 diff --git a/m4/as-compiler-flag.m4 b/m4/as-compiler-flag.m4 new file mode 100755 index 0000000..4134857 --- /dev/null +++ b/m4/as-compiler-flag.m4 @@ -0,0 +1,25 @@ +dnl as-compiler-flag.m4 0.0.1 +dnl autostars m4 macro for detection of compiler flags +dnl +dnl ds@schleef.org + +AC_DEFUN([AS_COMPILER_FLAG], +[ + AC_MSG_CHECKING([to see if compiler understands $1]) + + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $1" + + AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) + CFLAGS="$save_CFLAGS" + + if test "X$flag_ok" = Xyes ; then + $2 + true + else + $3 + true + fi + AC_MSG_RESULT([$flag_ok]) +]) + diff --git a/m4/as-version.m4 b/m4/as-version.m4 new file mode 100755 index 0000000..249102b --- /dev/null +++ b/m4/as-version.m4 @@ -0,0 +1,66 @@ +dnl as-version.m4 0.1.0 + +dnl autostars m4 macro for versioning + +dnl Thomas Vander Stichele + +dnl $Id: as-version.m4,v 1.2 2004-09-17 22:18:03 leroutier Exp $ + +dnl AS_VERSION(PACKAGE, PREFIX, MAJOR, MINOR, MICRO, NANO, +dnl ACTION-IF-NO-NANO, [ACTION-IF-NANO]) + +dnl example +dnl AS_VERSION(gstreamer, GST_VERSION, 0, 3, 2,) +dnl for a 0.3.2 release version + +dnl this macro +dnl - defines [$PREFIX]_MAJOR, MINOR and MICRO +dnl - if NANO is empty, then we're in release mode, else in cvs/dev mode +dnl - defines [$PREFIX], VERSION, and [$PREFIX]_RELEASE +dnl - executes the relevant action +dnl - AC_SUBST's PACKAGE, VERSION, [$PREFIX] and [$PREFIX]_RELEASE +dnl as well as the little ones +dnl - doesn't call AM_INIT_AUTOMAKE anymore because it prevents +dnl maintainer mode from running ok +dnl +dnl don't forget to put #undef [$2] and [$2]_RELEASE in acconfig.h +dnl if you use acconfig.h + +AC_DEFUN([AS_VERSION], +[ + PACKAGE=[$1] + [$2]_MAJOR=[$3] + [$2]_MINOR=[$4] + [$2]_MICRO=[$5] + NANO=[$6] + [$2]_NANO=$NANO + if test "x$NANO" = "x" || test "x$NANO" = "x0"; + then + AC_MSG_NOTICE(configuring [$1] for release) + VERSION=[$3].[$4].[$5] + [$2]_RELEASE=1 + dnl execute action + ifelse([$7], , :, [$7]) + else + AC_MSG_NOTICE(configuring [$1] for development with nano $NANO) + VERSION=[$3].[$4].[$5].$NANO + [$2]_RELEASE=0.`date +%Y%m%d.%H%M%S` + dnl execute action + ifelse([$8], , :, [$8]) + fi + + [$2]=$VERSION + AC_DEFINE_UNQUOTED([$2], "$[$2]", [Define the version]) + AC_SUBST([$2]) + AC_DEFINE_UNQUOTED([$2]_RELEASE, "$[$2]_RELEASE", [Define the release version]) + AC_SUBST([$2]_RELEASE) + + AC_SUBST([$2]_MAJOR) + AC_SUBST([$2]_MINOR) + AC_SUBST([$2]_MICRO) + AC_SUBST([$2]_NANO) + AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Define the package name]) + AC_SUBST(PACKAGE) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Define the version]) + AC_SUBST(VERSION) +]) diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec new file mode 100644 index 0000000..644e99d --- /dev/null +++ b/packaging/gst-plugins-tizen.spec @@ -0,0 +1,56 @@ +Name: gst-plugins-tizen1.0 +Version: 0.1.0 +Summary: GStreamer tizen plugins (common) +Release: 2 +Group: Multimedia/Framework +Url: http://gstreamer.freedesktop.org/ +License: LGPL-2.0+ +Source0: %{name}-%{version}.tar.gz +%define gst_branch 1.0 + +#BuildRequires: pkgconfig(camsrcjpegenc) +BuildRequires: pkgconfig(ecore) +BuildRequires: pkgconfig(ecore-x) +BuildRequires: pkgconfig(evas) +BuildRequires: pkgconfig(gstreamer-audio-1.0) +BuildRequires: pkgconfig(gstreamer-video-1.0) +BuildRequires: pkgconfig(gstreamer-plugins-base-1.0) +BuildRequires: pkgconfig(gstreamer-1.0) +BuildRequires: pkgconfig(libexif) +BuildRequires: pkgconfig(libdri2) +BuildRequires: pkgconfig(x11) +BuildRequires: pkgconfig(xext) +BuildRequires: pkgconfig(xv) +BuildRequires: pkgconfig(xdamage) +BuildRequires: pkgconfig(libdrm) +BuildRequires: pkgconfig(libtbm) +BuildRequires: libdrm-devel +BuildRequires: pkgconfig(dri2proto) +BuildRequires: pkgconfig(xfixes) +BuildRequires: pkgconfig(vconf) +#BuildRequires: pkgconfig(mm-scmirroring-common) + +%description +GStreamer tizen plugins (common) + +%prep +%setup -q + + +%build +export CFLAGS+=" -DGST_EXT_TIME_ANALYSIS -DGST_EXT_XV_ENHANCEMENT -DEXPORT_API=\"__attribute__((visibility(\\\"default\\\")))\" " + +./autogen.sh --disable-static +%configure --disable-static + +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +%make_install + + +%files +%manifest gst-plugins-tizen1.0.manifest +%defattr(-,root,root,-) +%{_libdir}/gstreamer-%{gst_branch}/*.so diff --git a/pdpushsrc/Makefile.am b/pdpushsrc/Makefile.am new file mode 100755 index 0000000..308a09c --- /dev/null +++ b/pdpushsrc/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/pdpushsrc/src/Makefile.am b/pdpushsrc/src/Makefile.am new file mode 100755 index 0000000..090c2d1 --- /dev/null +++ b/pdpushsrc/src/Makefile.am @@ -0,0 +1,26 @@ +# plugindir is set in configure + +############################################################################## +# change libgstplugin.la to something more suitable, e.g. libmysomething.la # +############################################################################## +plugin_LTLIBRARIES = libgstpdpushsrc.la + +############################################################################## +# for the next set of variables, rename the prefix if you renamed the .la, # +# e.g. libgstplugin_la_SOURCES => libmysomething_la_SOURCES # +# libgstplugin_la_CFLAGS => libmysomething_la_CFLAGS # +# libgstplugin_la_LIBADD => libmysomething_la_LIBADD # +# libgstplugin_la_LDFLAGS => libmysomething_la_LDFLAGS # +############################################################################## + +# sources used to compile this plug-in +libgstpdpushsrc_la_SOURCES = gstpdpushsrc.c + +# flags used to compile this plugin +# add other _CFLAGS and _LIBS as needed +libgstpdpushsrc_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) +libgstpdpushsrc_la_LIBADD = $(GST_LIBS) $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) +libgstpdpushsrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +# headers we need but don't want installed +noinst_HEADERS = gstpdpushsrc.h diff --git a/pdpushsrc/src/gstpdpushsrc.c b/pdpushsrc/src/gstpdpushsrc.c new file mode 100644 index 0000000..1df683d --- /dev/null +++ b/pdpushsrc/src/gstpdpushsrc.c @@ -0,0 +1,820 @@ +/* + * pdpushsrc + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Seungbae Shin + * + * 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 +#include "gstpdpushsrc.h" +#include +#include +#include +#ifdef G_OS_WIN32 +#include /* lseek, open, close, read */ +/* On win32, stat* default to 32 bit; we need the 64-bit + * variants, so explicitly define it that way. */ +#define stat __stat64 +#define fstat _fstat64 +#undef lseek +#define lseek _lseeki64 +#undef off_t +#define off_t guint64 +/* Prevent stat.h from defining the stat* functions as + * _stat*, since we're explicitly overriding that */ +#undef _INC_STAT_INL +#endif +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +/* FIXME we should be using glib for this */ +#ifndef S_ISREG +#define S_ISREG(mode) ((mode)&_S_IFREG) +#endif +#ifndef S_ISDIR +#define S_ISDIR(mode) ((mode)&_S_IFDIR) +#endif +#ifndef S_ISSOCK +#define S_ISSOCK(x) (0) +#endif +#ifndef O_BINARY +#define O_BINARY (0) +#endif + +static int +file_open (const gchar * filename, int flags, int mode) +{ + return open (filename, flags, mode); +} + +GST_DEBUG_CATEGORY_STATIC (gst_pd_pushsrc_debug); +#define GST_CAT_DEFAULT gst_pd_pushsrc_debug + +/* FileSrc signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +#define DEFAULT_BLOCKSIZE 4*1024 + +enum +{ + ARG_0, + ARG_LOCATION, + ARG_EOS, +}; + +static void gst_pd_pushsrc_finalize (GObject * object); + +static void gst_pd_pushsrc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); +static void gst_pd_pushsrc_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); + +static gboolean gst_pd_pushsrc_start (GstBaseSrc * basesrc); +static gboolean gst_pd_pushsrc_stop (GstBaseSrc * basesrc); + +static gboolean gst_pd_pushsrc_is_seekable (GstBaseSrc * src); +static gboolean gst_pd_pushsrc_get_size (GstBaseSrc * src, guint64 * size); +static gboolean gst_pd_pushsrc_query (GstBaseSrc * src, GstQuery * query); +static void gst_pd_pushsrc_uri_handler_init (gpointer g_iface, gpointer iface_data); +static GstFlowReturn gst_pd_pushsrc_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer); +static gboolean gst_pd_pushsrc_checkgetrange (GstPad * pad); + +G_DEFINE_TYPE_WITH_CODE (GstPDPushSrc, gst_pd_pushsrc, GST_TYPE_BASE_SRC, + G_IMPLEMENT_INTERFACE(GST_TYPE_URI_HANDLER, gst_pd_pushsrc_uri_handler_init)); + +static void +gst_pd_pushsrc_base_init (gpointer g_class) +{ + GST_LOG ("IN"); + + GST_LOG ("OUT"); +} + +static void +gst_pd_pushsrc_class_init (GstPDPushSrcClass * klass) +{ + GST_LOG ("IN"); + + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSrcClass *gstbasesrc_class; + + gobject_class = G_OBJECT_CLASS (klass); + gstelement_class = GST_ELEMENT_CLASS (klass); + gstbasesrc_class = GST_BASE_SRC_CLASS (klass); + + gobject_class->set_property = gst_pd_pushsrc_set_property; + gobject_class->get_property = gst_pd_pushsrc_get_property; + gobject_class->finalize = gst_pd_pushsrc_finalize; + + g_object_class_install_property (gobject_class, ARG_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, ARG_EOS, + g_param_spec_boolean ("eos", + "EOS recived on downloading pipeline", + "download of clip is over", + 0, + G_PARAM_READWRITE)); + + gst_element_class_set_details_simple (gstelement_class, + "PD push source", + "Source/File", + "Read from arbitrary point in a file", + "Naveen Ch "); + gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&srctemplate)); + + gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_pd_pushsrc_start); + gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_pd_pushsrc_stop); + gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_pd_pushsrc_is_seekable); + gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_pd_pushsrc_get_size); + gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_pd_pushsrc_query); + gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_pd_pushsrc_create); + + if (sizeof (off_t) < 8) { + GST_LOG ("No large file support, sizeof (off_t) = %" G_GSIZE_FORMAT "!", + sizeof (off_t)); + } + + GST_LOG ("OUT"); + +} + +static void +gst_pd_pushsrc_init (GstPDPushSrc * src) +{ + GST_LOG ("IN"); + GstBaseSrc *basesrc = GST_BASE_SRC (src); + + src->filename = NULL; + src->fd = 0; + src->uri = NULL; + src->is_regular = FALSE; + src->is_eos = FALSE; + + GST_LOG ("OUT"); +} + +static void +gst_pd_pushsrc_finalize (GObject * object) +{ + GST_LOG ("IN"); + + GstPDPushSrc *src; + + src = GST_PD_PUSHSRC (object); + + g_free (src->filename); + g_free (src->uri); + + G_OBJECT_CLASS (gst_pd_pushsrc_parent_class)->finalize (object); + + GST_LOG ("OUT"); +} + +static gboolean +gst_pd_pushsrc_set_location (GstPDPushSrc * src, const gchar * location) +{ + GST_LOG ("IN"); + + GstState state; + + /* the element must be stopped in order to do this */ + GST_OBJECT_LOCK (src); + state = GST_STATE (src); + if (state != GST_STATE_READY && state != GST_STATE_NULL) + goto wrong_state; + GST_OBJECT_UNLOCK (src); + + g_free (src->filename); + g_free (src->uri); + + /* clear the filename if we get a NULL (is that possible?) */ + if (location == NULL) { + src->filename = NULL; + src->uri = NULL; + } else { + /* we store the filename as received by the application. On Windows this + * should be UTF8 */ + src->filename = g_strdup (location); + src->uri = gst_filename_to_uri (location, NULL); + GST_INFO ("filename : %s", src->filename); + GST_INFO ("uri : %s", src->uri); + } + g_object_notify (G_OBJECT (src), "location"); + + GST_LOG ("OUT"); + + return TRUE; + + /* ERROR */ +wrong_state: + { + g_warning ("Changing the `location' property on filesrc when a file is " + "open is not supported."); + GST_OBJECT_UNLOCK (src); + GST_LOG ("OUT :: wrong_state"); + return FALSE; + } +} + +static void +gst_pd_pushsrc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GST_LOG ("IN"); + + GstPDPushSrc *src; + + g_return_if_fail (GST_IS_PD_PUSHSRC (object)); + + src = GST_PD_PUSHSRC (object); + + switch (prop_id) { + case ARG_LOCATION: + gst_pd_pushsrc_set_location (src, g_value_get_string (value)); + break; + case ARG_EOS: + src->is_eos = g_value_get_boolean (value); + g_print ("\n\n\nis_eos is becoming %d\n\n\n", src->is_eos); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + GST_LOG ("OUT"); +} + +static void +gst_pd_pushsrc_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GST_LOG ("IN"); + GstPDPushSrc *src; + + g_return_if_fail (GST_IS_PD_PUSHSRC (object)); + + src = GST_PD_PUSHSRC (object); + + switch (prop_id) { + case ARG_LOCATION: + g_value_set_string (value, src->filename); + break; + case ARG_EOS: + g_value_set_boolean (value, src->is_eos); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + GST_LOG ("OUT"); +} + +static GstFlowReturn +gst_pd_pushsrc_create_read (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer) +{ + GST_LOG ("IN"); + + int ret; + GstBuffer *buf = NULL; + GstMapInfo buf_info = GST_MAP_INFO_INIT; + struct stat stat_results; + GstPDPushSrc *src; + + src = GST_PD_PUSHSRC_CAST (basesrc); + + GST_LOG_OBJECT (src, "read position = %"G_GUINT64_FORMAT ", offset = %"G_GUINT64_FORMAT", length = %d", + src->read_position, offset, length); + + memset (&stat_results, 0, sizeof (stat_results)); + + if (fstat (src->fd, &stat_results) < 0) + goto could_not_stat; + + GST_LOG_OBJECT (src, "offset + length = %"G_GUINT64_FORMAT " and filesize = %"G_GUINT64_FORMAT, offset + length, stat_results.st_size); + + while ((offset + length) > stat_results.st_size) + { + fd_set fds; + int ret; + struct timeval timeout = {0,}; + guint64 avail_size = 0; + + if (src->is_eos) + goto eos; + + FD_ZERO (&fds); + FD_SET (src->fd, &fds); + + timeout.tv_sec = 0; + timeout.tv_usec = ((basesrc->blocksize * 8 * 1000) / 64000); // wait_time = (blocksize * 8) / (min downloadratei.e. 64Kbps) + + GST_DEBUG_OBJECT (src, "Going to wait for %ld msec", timeout.tv_usec); + + ret = select (src->fd + 1, &fds, NULL, NULL, &timeout); + if (-1 == ret) + { + GST_ERROR_OBJECT (src, "ERROR in select () : reason - %s...\n", strerror(errno)); + return GST_FLOW_ERROR; + } + else if (0 == ret) + { + GST_WARNING_OBJECT (src, "select () timeout happened..."); + } + else + { + memset (&stat_results, 0, sizeof (stat_results)); + + if (fstat (src->fd, &stat_results) < 0) + goto could_not_stat; + + avail_size = stat_results.st_size; + + GST_LOG_OBJECT (src, "Available data size in file = %"G_GUINT64_FORMAT, avail_size); + + if ((offset + length) > avail_size) + { + GST_LOG_OBJECT (src, "Enough data is NOT available..."); + } + else + { + GST_LOG_OBJECT (src, "Enough data is available..."); + } + } + } + + if (G_UNLIKELY (src->read_position != offset)) { + off_t res; + + res = lseek (src->fd, offset, SEEK_SET); + if (G_UNLIKELY (res < 0 || res != offset)) + goto seek_failed; + src->read_position = offset; + } + + buf = gst_buffer_new_and_alloc (length); + if (G_UNLIKELY (buf == NULL && length > 0)) { + GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", length); + return GST_FLOW_ERROR; + } + + /* No need to read anything if length is 0 */ + if (length > 0) { + GST_LOG_OBJECT (src, "Reading %d bytes at offset 0x%" G_GINT64_MODIFIER "x", + length, offset); + gst_buffer_map(buf, &buf_info, GST_MAP_WRITE); + ret = read (src->fd, buf_info.data, length); + gst_buffer_unmap(buf, &buf_info); + if (G_UNLIKELY (ret < 0)) + goto could_not_read; + + /* seekable regular files should have given us what we expected */ + if (G_UNLIKELY ((guint) ret < length && src->seekable)) + goto unexpected_eos; + + /* other files should eos if they read 0 and more was requested */ + if (G_UNLIKELY (ret == 0 && length > 0)) + goto eos; + + length = ret; + GST_BUFFER_OFFSET (buf) = offset; + GST_BUFFER_OFFSET_END (buf) = offset + length; + + src->read_position += length; + } + + *buffer = buf; + GST_LOG ("OUT"); + + return GST_FLOW_OK; + + /* ERROR */ +seek_failed: + { + GST_ERROR_OBJECT (src, "Seek failed..."); + GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM); + return GST_FLOW_ERROR; + } +could_not_stat: + { + GST_ERROR_OBJECT (src, "Could not stat"); + GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM); + return GST_FLOW_ERROR; + } +could_not_read: + { + GST_ERROR_OBJECT (src, "Could not read..."); + GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM); + if (buf) + gst_buffer_unref (buf); + return GST_FLOW_ERROR; + } +unexpected_eos: + { + GST_ERROR_OBJECT (src, "Unexpected EOS occured..."); + GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), ("unexpected end of file.")); + if (buf) + gst_buffer_unref (buf); + return GST_FLOW_ERROR; + } +eos: + { + GST_ERROR_OBJECT (src, "non-regular file hits EOS"); + if (buf) + gst_buffer_unref (buf); + return GST_FLOW_EOS; + } +} + +static GstFlowReturn +gst_pd_pushsrc_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer) +{ + GST_LOG ("IN"); + + GstPDPushSrc *pdsrc; + GstFlowReturn ret; + + pdsrc = GST_PD_PUSHSRC_CAST (basesrc); + ret = gst_pd_pushsrc_create_read (basesrc, offset, length, buffer); + GST_LOG ("OUT"); + + return ret; +} + +static gboolean +gst_pd_pushsrc_query (GstBaseSrc * basesrc, GstQuery * query) +{ + GST_LOG ("IN"); + + gboolean ret = FALSE; + GstPDPushSrc *src = GST_PD_PUSHSRC (basesrc); + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_URI: + gst_query_set_uri (query, src->uri); + ret = TRUE; + break; + + case GST_QUERY_SCHEDULING: + ret = gst_pd_pushsrc_checkgetrange(basesrc->srcpad); + break; + + default: + ret = FALSE; + break; + } + + if (!ret) + ret = GST_BASE_SRC_CLASS (gst_pd_pushsrc_parent_class)->query (basesrc, query); + GST_LOG ("OUT"); + + return ret; +} + +static gboolean +gst_pd_pushsrc_checkgetrange (GstPad * pad) +{ + GST_LOG ("IN"); + + GST_LOG ("OUT"); + + return FALSE; +} + +static gboolean +gst_pd_pushsrc_is_seekable (GstBaseSrc * basesrc) +{ + GST_LOG ("IN"); + + GstPDPushSrc *src = GST_PD_PUSHSRC (basesrc); + + GST_DEBUG_OBJECT (src, "seekable = %d", src->seekable); + GST_LOG ("OUT"); + + return src->seekable; + +} + +static gboolean +gst_pd_pushsrc_get_size (GstBaseSrc * basesrc, guint64 * size) +{ + GST_LOG ("IN"); + + struct stat stat_results; + GstPDPushSrc *src; + + src = GST_PD_PUSHSRC (basesrc); + + if (!src->seekable) { + /* If it isn't seekable, we won't know the length (but fstat will still + * succeed, and wrongly say our length is zero. */ + return FALSE; + } + + if (fstat (src->fd, &stat_results) < 0) + goto could_not_stat; + + //*size = stat_results.st_size; + /* Naveen : Intentionally, doing this because we dont know the file size...because its keep on increasing in PD case */ + *size = G_MAXUINT64; + + GST_DEBUG ("size of the file = %"G_GUINT64_FORMAT, *size); + + GST_LOG ("OUT"); + + return TRUE; + + /* ERROR */ +could_not_stat: + { + GST_ERROR_OBJECT (src, "Could not stat"); + return FALSE; + } +} + +/* open the file, necessary to go to READY state */ +static gboolean +gst_pd_pushsrc_start (GstBaseSrc * basesrc) +{ + GST_LOG ("IN"); + + GstPDPushSrc *src = GST_PD_PUSHSRC (basesrc); + struct stat stat_results; + + if (src->filename == NULL || src->filename[0] == '\0') + goto no_filename; + + GST_INFO_OBJECT (src, "opening file %s", src->filename); + + /* open the file */ + src->fd = file_open (src->filename, O_RDONLY | O_BINARY, 0); + + if (src->fd < 0) + goto open_failed; + + /* check if it is a regular file, otherwise bail out */ + if (fstat (src->fd, &stat_results) < 0) + goto no_stat; + + if (S_ISDIR (stat_results.st_mode)) + goto was_directory; + + if (S_ISSOCK (stat_results.st_mode)) + goto was_socket; + + src->read_position = 0; + + /* record if it's a regular (hence seekable and lengthable) file */ + if (S_ISREG (stat_results.st_mode)) + src->is_regular = TRUE; + + { + /* we need to check if the underlying file is seekable. */ + off_t res = lseek (src->fd, 0, SEEK_END); + + if (res < 0) { + GST_LOG_OBJECT (src, "disabling seeking, not in mmap mode and lseek " + "failed: %s", g_strerror (errno)); + src->seekable = FALSE; + } else { + src->seekable = TRUE; + } + lseek (src->fd, 0, SEEK_SET); + } + + /* We can only really do seeking on regular files - for other file types, we + * don't know their length, so seeking isn't useful/meaningful */ + src->seekable = src->seekable && src->is_regular; + GST_LOG ("OUT"); + + return TRUE; + + /* ERROR */ +no_filename: + { + GST_ERROR_OBJECT (src, "No file name specified for reading..."); + GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, + ("No file name specified for reading."), (NULL)); + return FALSE; + } +open_failed: + { + switch (errno) { + case ENOENT: + GST_ERROR_OBJECT (src, "File could not be found"); + GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), + ("No such file \"\"")); + break; + default: + GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, + ("Could not open file for reading."), + GST_ERROR_SYSTEM); + break; + } + return FALSE; + } +no_stat: + { + GST_ERROR_OBJECT (src, "Could not get stat info..."); + GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, + ("Could not get info on \"\"."), (NULL)); + close (src->fd); + return FALSE; + } +was_directory: + { + GST_ERROR_OBJECT (src, "Is a Directory"); + GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, + ("\"\" is a directory."), (NULL)); + close (src->fd); + return FALSE; + } +was_socket: + { + GST_ERROR_OBJECT (src, "Is a Socket"); + GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, + ("File \"\" is a socket."), (NULL)); + close (src->fd); + return FALSE; + } +} + +/* unmap and close the file */ +static gboolean +gst_pd_pushsrc_stop (GstBaseSrc * basesrc) +{ + GST_LOG ("IN"); + + GstPDPushSrc *src = GST_PD_PUSHSRC (basesrc); + + /* close the file */ + close (src->fd); + + /* zero out a lot of our state */ + src->fd = 0; + src->is_regular = FALSE; + + GST_LOG ("OUT"); + + return TRUE; +} + +/*** GSTURIHANDLER INTERFACE *************************************************/ + +static GstURIType +gst_pd_pushsrc_uri_get_type (GType type) +{ + GST_LOG ("IN"); + GST_LOG ("OUT"); + + return GST_URI_SRC; +} + +static const gchar * const* +gst_pd_pushsrc_uri_get_protocols (GType type) +{ + GST_LOG ("IN"); + static const gchar *protocols[] = { "file", NULL }; + GST_LOG ("OUT"); + + return protocols; +} + +static gchar * +gst_pd_pushsrc_uri_get_uri (GstURIHandler * handler) +{ + GST_LOG ("IN"); + GstPDPushSrc *src = GST_PD_PUSHSRC (handler); + GST_LOG ("OUT"); + + return g_strdup(src->uri); +} + +static gboolean +gst_pd_pushsrc_uri_set_uri (GstURIHandler * handler, const gchar * uri, GError ** error) +{ + GST_LOG ("IN"); + + gchar *location, *hostname = NULL; + gboolean ret = FALSE; + GstPDPushSrc *src = GST_PD_PUSHSRC (handler); + + if (strcmp (uri, "file://") == 0) { + /* Special case for "file://" as this is used by some applications + * to test with gst_element_make_from_uri if there's an element + * that supports the URI protocol. */ + gst_pd_pushsrc_set_location (src, NULL); + return TRUE; + } + + location = g_filename_from_uri (uri, &hostname, error); + + if (!location || *error) { + if (*error) { + GST_WARNING_OBJECT (src, "Invalid URI '%s' for filesrc: %s", uri, + (*error)->message); + } else { + GST_WARNING_OBJECT (src, "Invalid URI '%s' for filesrc", uri); + } + goto beach; + } + + if ((hostname) && (strcmp (hostname, "localhost"))) { + /* Only 'localhost' is permitted */ + GST_WARNING_OBJECT (src, "Invalid hostname '%s' for filesrc", hostname); + goto beach; + } +#ifdef G_OS_WIN32 + /* Unfortunately, g_filename_from_uri() doesn't handle some UNC paths + * correctly on windows, it leaves them with an extra backslash + * at the start if they're of the mozilla-style file://///host/path/file + * form. Correct this. + */ + if (location[0] == '\\' && location[1] == '\\' && location[2] == '\\') + g_memmove (location, location + 1, strlen (location + 1) + 1); +#endif + + ret = gst_pd_pushsrc_set_location (src, location); + + GST_LOG ("OUT"); + +beach: + if (location) + g_free (location); + if (hostname) + g_free (hostname); + + return ret; +} + +static void +gst_pd_pushsrc_uri_handler_init (gpointer g_iface, gpointer iface_data) +{ + GST_LOG ("IN"); + GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; + + iface->get_type = gst_pd_pushsrc_uri_get_type; + iface->get_protocols = gst_pd_pushsrc_uri_get_protocols; + iface->get_uri = gst_pd_pushsrc_uri_get_uri; + iface->set_uri = gst_pd_pushsrc_uri_set_uri; + GST_LOG ("OUT"); +} + +static gboolean +gst_pd_pushsrc_plugin_init (GstPlugin *plugin) +{ + if (!gst_element_register (plugin, "pdpushsrc", GST_RANK_NONE, gst_pd_pushsrc_get_type())) + { + return FALSE; + } + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + pdpushsrc, + "PD push source", + gst_pd_pushsrc_plugin_init, + VERSION, + "LGPL", + "Samsung Electronics Co", + "http://www.samsung.com") + + diff --git a/pdpushsrc/src/gstpdpushsrc.h b/pdpushsrc/src/gstpdpushsrc.h new file mode 100755 index 0000000..651efdb --- /dev/null +++ b/pdpushsrc/src/gstpdpushsrc.h @@ -0,0 +1,73 @@ +/* + * pdpushsrc + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Seungbae Shin + * + * 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_PD_PUSHSRC_H__ +#define __GST_PD_PUSHSRC_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_PD_PUSHSRC (gst_pd_pushsrc_get_type()) +#define GST_PD_PUSHSRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PD_PUSHSRC,GstPDPushSrc)) +#define GST_PD_PUSHSRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PD_PUSHSRC,GstPDPushSrcClass)) +#define GST_IS_PD_PUSHSRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PD_PUSHSRC)) +#define GST_IS_PD_PUSHSRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PD_PUSHSRC)) +#define GST_PD_PUSHSRC_CAST(obj) ((GstPDPushSrc*) obj) + +typedef struct _GstPDPushSrc GstPDPushSrc; +typedef struct _GstPDPushSrcClass GstPDPushSrcClass; + +/** + * GstFileSrc: + * + * Opaque #GstPDPushSrc structure. + */ +struct _GstPDPushSrc { + GstBaseSrc element; + GstPad *srcpad; + + gchar *filename; /* filename */ + gchar *uri; /* caching the URI */ + gint fd; /* open file descriptor */ + guint64 read_position; /* position of fd */ + + gboolean seekable; /* whether the file is seekable */ + gboolean is_regular; /* whether it's a (symlink to a) regular file */ + + gboolean is_eos; + +}; + +struct _GstPDPushSrcClass { + GstBaseSrcClass parent_class; +}; + +GType gst_pd_pushsrc_get_type (void); + +G_END_DECLS + +#endif /* __GST_FILE_SRC_H__ */ diff --git a/toggle/Makefile.am b/toggle/Makefile.am new file mode 100755 index 0000000..308a09c --- /dev/null +++ b/toggle/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/toggle/src/Makefile.am b/toggle/src/Makefile.am new file mode 100755 index 0000000..4d761d7 --- /dev/null +++ b/toggle/src/Makefile.am @@ -0,0 +1,30 @@ +# plugindir is set in configure + +############################################################################## +# change libgstplugin.la to something more suitable, e.g. libmysomething.la # +############################################################################## +plugin_LTLIBRARIES = libgsttoggle.la + +############################################################################## +# for the next set of variables, rename the prefix if you renamed the .la, # +# e.g. libgstplugin_la_SOURCES => libmysomething_la_SOURCES # +# libgstplugin_la_CFLAGS => libmysomething_la_CFLAGS # +# libgstplugin_la_LIBADD => libmysomething_la_LIBADD # +# libgstplugin_la_LDFLAGS => libmysomething_la_LDFLAGS # +############################################################################## + +# sources used to compile this plug-in +libgsttoggle_la_SOURCES = gsttoggle.c + + + +# flags used to compile this plugin +# add other _CFLAGS and _LIBS as needed +libgsttoggle_la_CFLAGS = $(GST_CFLAGS) +libgsttoggle_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) +#libgsttoggle_la_LIBADD = $(GST_BASE_LIBS) +libgsttoggle_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +# headers we need but don't want installed +noinst_HEADERS = gsttoggle.h + diff --git a/toggle/src/gsttoggle.c b/toggle/src/gsttoggle.c new file mode 100755 index 0000000..0363dda --- /dev/null +++ b/toggle/src/gsttoggle.c @@ -0,0 +1,210 @@ +/* + * toggle + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * 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 + +#include "gsttoggle.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_mytoggle_debug); +#define GST_CAT_DEFAULT gst_mytoggle_debug + +enum +{ + LAST_SIGNAL +}; + + +#define DEFAULT_BLOCK_DATA FALSE + +enum +{ + PROP_0, + PROP_BLOCK_DATA + +}; + + +#define _do_init(bla) \ + GST_DEBUG_CATEGORY_INIT (gst_mytoggle_debug, "toggle", 0, "toggle element"); + +G_DEFINE_TYPE_WITH_CODE (GstMytoggle, gst_mytoggle, + GST_TYPE_BASE_TRANSFORM, _do_init(G_TYPE_INVALID)); + +static void gst_mytoggle_finalize (GObject * object); +static void gst_mytoggle_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_mytoggle_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static GstFlowReturn gst_mytoggle_transform_ip (GstBaseTransform * trans, + GstBuffer * buf); +static gboolean gst_mytoggle_start (GstBaseTransform * trans); +static gboolean gst_mytoggle_stop (GstBaseTransform * trans); + +static void +gst_mytoggle_base_init (gpointer g_class) +{ +} + +static void +gst_mytoggle_finalize (GObject * object) +{ + GstMytoggle *mytoggle; + + G_OBJECT_CLASS (gst_mytoggle_parent_class)->finalize (object); +} + +static void +gst_mytoggle_class_init (GstMytoggleClass * klass) +{ + GObjectClass *gobject_class; + GstBaseTransformClass *gstbasetrans_class; + GstElementClass *gstelement_class; + + gobject_class = G_OBJECT_CLASS (klass); + gstbasetrans_class = GST_BASE_TRANSFORM_CLASS (klass); + gstelement_class = GST_ELEMENT_CLASS (klass); + + gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_mytoggle_set_property); + gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_mytoggle_get_property); + + g_object_class_install_property (gobject_class, + PROP_BLOCK_DATA, g_param_spec_boolean ("block_data", + "Data Block", + "Data Block", + DEFAULT_BLOCK_DATA, G_PARAM_READWRITE)); + + gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_mytoggle_finalize); + + gst_element_class_set_details_simple (gstelement_class, + "toggle", + "Generic", + "Pass data without modification", "Rahul Mittal "); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&srctemplate)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&sinktemplate)); + + gstbasetrans_class->transform_ip = + GST_DEBUG_FUNCPTR (gst_mytoggle_transform_ip); + gstbasetrans_class->start = GST_DEBUG_FUNCPTR (gst_mytoggle_start); + gstbasetrans_class->stop = GST_DEBUG_FUNCPTR (gst_mytoggle_stop); +} + +static void +gst_mytoggle_init (GstMytoggle * mytoggle) +{ + gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (mytoggle), TRUE); + + mytoggle->block_data = DEFAULT_BLOCK_DATA; + +} + +static GstFlowReturn +gst_mytoggle_transform_ip (GstBaseTransform * trans, GstBuffer * buf) +{ + GstMytoggle *mytoggle = GST_MYTOGGLE (trans); + + if (mytoggle->block_data ==TRUE) + return GST_BASE_TRANSFORM_FLOW_DROPPED; + + return GST_FLOW_OK; +} + +static void +gst_mytoggle_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstMytoggle *mytoggle; + + mytoggle = GST_MYTOGGLE (object); + + switch (prop_id) { + + case PROP_BLOCK_DATA: + mytoggle->block_data = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_mytoggle_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstMytoggle *mytoggle; + + mytoggle = GST_MYTOGGLE (object); + + switch (prop_id) { + case PROP_BLOCK_DATA: + g_value_set_boolean (value, mytoggle->block_data); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_mytoggle_start (GstBaseTransform * trans) +{ + return TRUE; +} + +static gboolean +gst_mytoggle_stop (GstBaseTransform * trans) +{ + return TRUE; +} + + +static gboolean plugin_init(GstPlugin *plugin) +{ + + GST_DEBUG_CATEGORY_INIT (gst_mytoggle_debug, "toggle",0, "toggle"); + return gst_element_register (plugin, "toggle", GST_RANK_NONE, GST_TYPE_MYTOGGLE); +} +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + toggle, + "Base transform plugin template", + plugin_init, VERSION, "LGPL", "Samsung Electronics Co", "http://www.samsung.com/") + + diff --git a/toggle/src/gsttoggle.h b/toggle/src/gsttoggle.h new file mode 100755 index 0000000..0090a6b --- /dev/null +++ b/toggle/src/gsttoggle.h @@ -0,0 +1,61 @@ +/* + * toggle + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * 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_MYTOGGLE_H__ +#define __GST_MYTOGGLE_H__ + + +#include +#include + +G_BEGIN_DECLS + + +#define GST_TYPE_MYTOGGLE \ + (gst_mytoggle_get_type()) +#define GST_MYTOGGLE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MYTOGGLE,GstMytoggle)) +#define GST_MYTOGGLE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MYTOGGLE,GstMytoggleClass)) +#define GST_IS_MYTOGGLE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MYTOGGLE)) +#define GST_IS_MYTOGGLE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MYTOGGLE)) + +typedef struct _GstMytoggle GstMytoggle; +typedef struct _GstMytoggleClass GstMytoggleClass; + +struct _GstMytoggle { + GstBaseTransform element; + gboolean block_data; +}; + +struct _GstMytoggleClass { + GstBaseTransformClass parent_class; +}; + +GType gst_mytoggle_get_type(void); + +G_END_DECLS + +#endif /* __GST_MYTOGGLE_H__ */ diff --git a/wfdrtspsrc/Makefile.am b/wfdrtspsrc/Makefile.am new file mode 100755 index 0000000..308a09c --- /dev/null +++ b/wfdrtspsrc/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/wfdrtspsrc/src/Makefile.am b/wfdrtspsrc/src/Makefile.am new file mode 100755 index 0000000..e8e5600 --- /dev/null +++ b/wfdrtspsrc/src/Makefile.am @@ -0,0 +1,35 @@ +plugin_LTLIBRARIES = libgstwfdrtspsrc.la + +libgstwfdrtspsrc_la_SOURCES = gstwfdrtspsrc.c gstwfdrtspext.c +libgstwfdrtspsrc_la_SOURCES += wfdrtspmanager.c + +libgstwfdrtspsrc_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(VCONF_FLAGS) + +libgstwfdrtspsrc_la_LIBADD = $(GST_LIBS) $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + $(MM_WFD_COMMON_LIBS) \ + -lgstrtp-@GST_MAJORMINOR@ -lgstrtsp-@GST_MAJORMINOR@ \ + $(WIN32_LIBS) \ + $(VCONF_LIBS) + +libgstwfdrtspsrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstwfdrtspsrc_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = gstwfdrtspsrc.h \ + gstwfdrtspext.h +noinst_HEADERS += wfdrtspmanager.h + +plugin_LTLIBRARIES += libgstwfdrtprequester.la + +libgstwfdrtprequester_la_SOURCES = gstwfdrtprequester.c + +libgstwfdrtprequester_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(VCONF_FLAGS) $(MM_WFD_COMMON_CFLAGS) +libgstwfdrtprequester_la_LIBADD = $(GST_LIBS) $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ + $(MM_WFD_COMMON_LIBS) \ + -lgstrtp-@GST_MAJORMINOR@ -lgstrtsp-@GST_MAJORMINOR@ \ + $(WIN32_LIBS) \ + $(VCONF_LIBS) +libgstwfdrtprequester_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstwfdrtprequester_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = gstwfdrtprequester.h + diff --git a/wfdrtspsrc/src/gstwfdrtprequester.c b/wfdrtspsrc/src/gstwfdrtprequester.c new file mode 100755 index 0000000..86e5a8b --- /dev/null +++ b/wfdrtspsrc/src/gstwfdrtprequester.c @@ -0,0 +1,1195 @@ +/* + * wfdrtprequester + * + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * 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 +#endif + +#include +#include +#include +#include + +#include "gstwfdrtprequester.h" + +GST_DEBUG_CATEGORY_STATIC (wfdrtprequester_debug); +#define GST_CAT_DEFAULT (wfdrtprequester_debug) + +/* signals and args */ +enum +{ + SIGNAL_REQUEST_TIMEOUT, + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_DO_REQUEST, + PROP_SSRC, + PROP_PT, + PROP_TIMEOUT +}; + +#define DEFAULT_DO_REQUEST TRUE +#define DEFAULT_SSRC 0x0000 +#define DEFAULT_PT 33 //MP2t-ES payload type +#define DEFAULT_TIMEOUT_MS 200 + + /* sink pads */ +static GstStaticPadTemplate rtp_sink_template = +GST_STATIC_PAD_TEMPLATE ("rtp_sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp") + ); + +static GstStaticPadTemplate retransmitted_rtp_sink_template = +GST_STATIC_PAD_TEMPLATE ("retransmitted_rtp_sink", + GST_PAD_SINK, + GST_PAD_REQUEST, + GST_STATIC_CAPS ("application/x-rtp") + ); + +/* src pads */ +static GstStaticPadTemplate rtp_src_template = +GST_STATIC_PAD_TEMPLATE ("rtp_src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp") + ); + +static GstStaticPadTemplate rtcp_src_template = +GST_STATIC_PAD_TEMPLATE ("rtcp_src", + GST_PAD_SRC, + GST_PAD_SOMETIMES, + GST_STATIC_CAPS ("application/x-rtcp") + ); + + +#define GST_WFD_RTP_REQUESTER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_WFD_RTP_REQUESTER, GstWFDRTPRequesterPrivate)) + +#define GST_WFD_RTP_REQUESTER_LOCK(requester) g_mutex_lock ((requester)->priv->lock) +#define GST_WFD_RTP_REQUESTER_UNLOCK(requester) g_mutex_unlock ((requester)->priv->lock) + +struct _GstWFDRTPRequesterPrivate +{ + GMutex *lock; + + gboolean flushing; + + /* the next expected seqnum we receive */ + guint64 next_in_seqnum; + + /* for checking requeting timeout */ + GList *request_ranges; + GTimer *timer; + guint timeout_checker_id; +}; + +typedef struct _GstWFDRTPRequestRange GstWFDRTPRequestRange; +struct _GstWFDRTPRequestRange +{ + guint16 start_seqnum; + guint16 end_seqnum; + + guint request_packet_num; + guint retransmitted_packet_num; + + gdouble request_time; +}; + + +/* + * The maximum number of missing packets we tollerate. These are packets with a + * sequence number bigger than the last seen packet. + */ +#define REQUESTER_MAX_DROPOUT 1024 +/* + * The maximum number of misordered packets we tollerate. These are packets with + * a sequence number smaller than the last seen packet. + */ +#define REQUESTER_MAX_MISORDER 16 + +#define REQUESTER_MTU_SIZE 1400 /* bytes */ + +#define gst_wfd_rtp_requester_parent_class parent_class + +/* GObject vmethods */ +static void gst_wfd_rtp_requester_finalize (GObject * object); +static void gst_wfd_rtp_requester_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_wfd_rtp_requester_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static gboolean gst_wfd_rtp_requester_sink_event (GstPad * pad, GstObject * parent, GstEvent * event); +static gboolean gst_wfd_rtp_requester_sink_newcaps (GstPad * pad, GstEvent *event); +static gboolean gst_wfd_rtp_requester_sink_event_retransmitted_rtp (GstPad * pad, GstObject * parent, GstEvent * event); +static gboolean gst_wfd_rtp_requester_src_event_rtcp (GstPad * pad, GstObject *parent, GstEvent * event); + +/* GstElement vmethods */ +static GstFlowReturn gst_wfd_rtp_requester_chain (GstPad * pad, GstObject *parent, GstBuffer * buf); +static GstPad *gst_wfd_rtp_requester_request_new_pad (GstElement * element, + GstPadTemplate * templ, const gchar * name, const GstCaps *caps); +static void gst_wfd_rtp_requester_release_pad (GstElement * element, GstPad * pad); + +static GstFlowReturn gst_wfd_rtp_requester_chain_retransmitted_rtp (GstPad * pad, GstObject *parent, GstBuffer * buf); + +static void gst_wfd_rtp_requester_flush_start (GstWFDRTPRequester * requester); +static void gst_wfd_rtp_requester_flush_stop (GstWFDRTPRequester * requester); + + +static guint gst_wfd_rtp_requester_signals[LAST_SIGNAL] = { 0 }; + +/* GObject vmethod implementations */ +static void +_do_init (GType wfdrtprequester_type) +{ + GST_DEBUG_CATEGORY_INIT (wfdrtprequester_debug, "wfdrtprequester", 0, "WFD RTP Requester"); +} + +G_DEFINE_TYPE_WITH_CODE (GstWFDRTPRequester, gst_wfd_rtp_requester, GST_TYPE_ELEMENT, _do_init((g_define_type_id))); + +/* initialize the plugin's class */ +static void +gst_wfd_rtp_requester_class_init (GstWFDRTPRequesterClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + g_type_class_add_private (klass, sizeof (GstWFDRTPRequesterPrivate)); + + gobject_class->finalize = gst_wfd_rtp_requester_finalize; + gobject_class->set_property = gst_wfd_rtp_requester_set_property; + gobject_class->get_property = gst_wfd_rtp_requester_get_property; + + g_object_class_install_property (gobject_class, PROP_DO_REQUEST, + g_param_spec_boolean ("do-request", "Do request", + "Request RTP retransmission", + DEFAULT_DO_REQUEST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_SSRC, + g_param_spec_uint ("ssrc", "SSRC", + "The SSRC of the RTP packets", 0, G_MAXUINT32, + DEFAULT_SSRC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_PT, + g_param_spec_uint ("pt", "payload type", + "The payload type of the RTP packets", 0, 0x80, DEFAULT_PT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstWFDRTPRequester::timeout: + * + * The maximum timeout of the requester. Packets should be retransmitted + * at most this time. Unless, the request-timeout signal will be emit. + */ + g_object_class_install_property (gobject_class, PROP_TIMEOUT, + g_param_spec_uint ("timeout", "Retransmssion timeout in ms", + "Timeout in ms for retransmission", 0, G_MAXUINT, DEFAULT_TIMEOUT_MS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstWFDRTPRequester::request-timeout: + * @req: a #GstWFDRTPRequester + * + * Notify of timeout which is requesting rtp retransmission. + */ + gst_wfd_rtp_requester_signals[SIGNAL_REQUEST_TIMEOUT] = + g_signal_new ("request-timeout", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstWFDRTPRequesterClass, request_timeout), NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); + + gst_element_class_set_details_simple (gstelement_class, "Request lost rtp packets", + "Source/Network", + "Request retransmition of lost rtp packets over network", + "Santhoshi KS "); + + + gstelement_class->request_new_pad = + GST_DEBUG_FUNCPTR (gst_wfd_rtp_requester_request_new_pad); + gstelement_class->release_pad = + GST_DEBUG_FUNCPTR (gst_wfd_rtp_requester_release_pad); + + /* sink pads */ + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&rtp_sink_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&retransmitted_rtp_sink_template)); + /* src pads */ + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&rtp_src_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&rtcp_src_template)); +} + +static void +gst_wfd_rtp_requester_init (GstWFDRTPRequester * requester) +{ + requester->priv = GST_WFD_RTP_REQUESTER_GET_PRIVATE(requester); + requester->priv->lock = g_mutex_new (); + requester->priv->flushing = FALSE; + requester->priv->next_in_seqnum = GST_CLOCK_TIME_NONE; + requester->priv->timer = NULL; + requester->priv->timeout_checker_id = 0; + requester->priv->request_ranges = NULL; + + requester->rtp_sink = gst_pad_new_from_static_template (&rtp_sink_template, "rtp_sink"); + gst_pad_set_event_function (requester->rtp_sink, + GST_DEBUG_FUNCPTR(gst_wfd_rtp_requester_sink_event)); + gst_pad_set_chain_function (requester->rtp_sink, + GST_DEBUG_FUNCPTR(gst_wfd_rtp_requester_chain)); + gst_element_add_pad (GST_ELEMENT (requester), requester->rtp_sink); + + requester->rtp_src = gst_pad_new_from_static_template (&rtp_src_template, "rtp_src"); + gst_element_add_pad (GST_ELEMENT (requester), requester->rtp_src); + + requester->do_request = DEFAULT_DO_REQUEST; + requester->ssrc = DEFAULT_SSRC; + requester->pt = DEFAULT_PT; + requester->timeout_ms = DEFAULT_TIMEOUT_MS; + requester->timeout_ns = requester->timeout_ms * GST_MSECOND; + + return; +} + +static void +gst_wfd_rtp_requester_finalize (GObject * object) +{ + GstWFDRTPRequester *requester = GST_WFD_RTP_REQUESTER (object); + GList *walk; + + requester = GST_WFD_RTP_REQUESTER (object); + + if (requester->priv->lock) { + g_mutex_free(requester->priv->lock); + requester->priv->lock = NULL; + } + + if (requester->priv->request_ranges) { + g_list_free (requester->priv->request_ranges); + requester->priv->request_ranges = NULL; + } + + for (walk = requester->priv->request_ranges; walk; walk = g_list_next (walk)) { + GstWFDRTPRequestRange *range = (GstWFDRTPRequestRange *) walk->data; + g_free (range); + } + g_list_free (requester->priv->request_ranges); + requester->priv->request_ranges = NULL; + + if (requester->priv->timeout_checker_id) + g_source_remove (requester->priv->timeout_checker_id); + requester->priv->timeout_checker_id = 0; + + if (requester->priv->timer) + g_timer_destroy (requester->priv->timer); + requester->priv->timer = NULL; + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_wfd_rtp_requester_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstWFDRTPRequester *requester = GST_WFD_RTP_REQUESTER (object); + + switch (prop_id) { + case PROP_DO_REQUEST: + requester->do_request = g_value_get_boolean (value); + break; + case PROP_SSRC: + requester->ssrc = g_value_get_uint (value); + break; + case PROP_PT: + requester->pt = g_value_get_uint (value); + break; + case PROP_TIMEOUT: + requester->timeout_ms = g_value_get_uint (value); + requester->timeout_ns = requester->timeout_ms * GST_MSECOND; + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_wfd_rtp_requester_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstWFDRTPRequester *requester = GST_WFD_RTP_REQUESTER (object); + + switch (prop_id) { + case PROP_DO_REQUEST: + g_value_set_boolean (value, requester->do_request); + break; + case PROP_SSRC: + g_value_set_uint (value, requester->ssrc); + break; + case PROP_PT: + g_value_set_uint (value, requester->pt); + break; + case PROP_TIMEOUT: + g_value_set_uint (value, requester->timeout_ms); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_wfd_rtp_requester_sink_newcaps (GstPad * pad, GstEvent *event) +{ + GstWFDRTPRequester *requester; + gboolean res = TRUE; + GstCaps *caps; + + requester = GST_WFD_RTP_REQUESTER (gst_pad_get_parent (pad)); + gst_event_parse_caps (event, &caps); + + gst_object_unref (requester); + + return res; +} + +/* GstElement vmethod implementations */ + +/* this function handles sink events */ +static gboolean +gst_wfd_rtp_requester_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) +{ + gboolean ret = FALSE; + GstWFDRTPRequester *requester = NULL; + + requester = GST_WFD_RTP_REQUESTER_CAST (gst_pad_get_parent (pad)); + if(requester == NULL) + { + GST_ERROR_OBJECT(requester, "requester is NULL."); + return ret; + } + + GST_DEBUG_OBJECT (requester, "requester got event %s", GST_EVENT_TYPE_NAME(event)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_START: + gst_wfd_rtp_requester_flush_start (requester); + ret = gst_pad_push_event (requester->rtp_src, event); + break; + case GST_EVENT_FLUSH_STOP: + ret = gst_pad_push_event (requester->rtp_src, event); + gst_wfd_rtp_requester_flush_stop (requester); + break; + case GST_EVENT_CAPS: + gst_wfd_rtp_requester_sink_newcaps (pad, event); + ret = gst_pad_push_event (requester->rtp_src, event); + break; + default: + ret = gst_pad_event_default (pad, parent, event); + break; + } + + gst_object_unref (requester); + + return ret; +} + +static void +gst_wfd_rtp_requester_flush_start (GstWFDRTPRequester * requester) +{ + GstWFDRTPRequesterPrivate *priv; + + priv = GST_WFD_RTP_REQUESTER_GET_PRIVATE(requester); + + /* mark ourselves as flushing */ + priv->flushing = TRUE; + GST_DEBUG_OBJECT (requester, "flush start.."); +} + +static void +gst_wfd_rtp_requester_flush_stop (GstWFDRTPRequester * requester) +{ + GstWFDRTPRequesterPrivate *priv; + GList *walk; + + priv = GST_WFD_RTP_REQUESTER_GET_PRIVATE(requester); + + GST_DEBUG_OBJECT (requester, "flush stop..."); + /* Mark as non flushing */ + priv->flushing = FALSE; + + priv->next_in_seqnum = GST_CLOCK_TIME_NONE; + + for (walk = priv->request_ranges; walk; walk = g_list_next (walk)) { + GstWFDRTPRequestRange *range = (GstWFDRTPRequestRange *) walk->data; + g_free (range); + } + g_list_free (priv->request_ranges); + priv->request_ranges = NULL; + + requester->ssrc = 0; + requester->pt = 0; +} + +static gboolean +gst_wfd_rtp_requester_sink_event_retransmitted_rtp (GstPad * pad, GstObject * parent, GstEvent * event) +{ + gboolean ret; + GstWFDRTPRequester * requester; + + requester = GST_WFD_RTP_REQUESTER_CAST (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT (requester, "requester got event %s", GST_EVENT_TYPE_NAME(event)); + + switch (GST_EVENT_TYPE (event)) { + default: + ret = gst_pad_event_default (pad, parent, event); + break; + } + + gst_object_unref (requester); + + return ret; +} + +static gboolean +gst_wfd_rtp_requester_src_event_rtcp (GstPad * pad, GstObject * parent, GstEvent * event) +{ + GstWFDRTPRequester * requester; + gboolean ret; + + requester = GST_WFD_RTP_REQUESTER_CAST (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT (requester, "requester got event %s", GST_EVENT_TYPE_NAME(event)); + + switch (GST_EVENT_TYPE (event)) { + default: + ret = gst_pad_event_default (pad, parent, event); + break; + } + + gst_object_unref (requester); + return ret; +} + +static gboolean +check_timeout (gpointer *data) +{ + GstWFDRTPRequester *requester = (GstWFDRTPRequester*)data; + GstWFDRTPRequesterPrivate *priv; + gboolean is_timeout = FALSE; + gboolean ret = TRUE; + GList *walk; + gdouble elapsed; + + priv = GST_WFD_RTP_REQUESTER_GET_PRIVATE(requester); + + if (priv->flushing) { + if (!g_source_remove (priv->timeout_checker_id)) + GST_DEBUG_OBJECT (requester, "fail to remove timer_id"); + priv->timeout_checker_id = 0; + ret = FALSE; + goto stop; + } + + if (!priv->request_ranges) { + GST_DEBUG_OBJECT (requester, "stop checking timeout due to no request"); + if (!g_source_remove (priv->timeout_checker_id)) + GST_DEBUG_OBJECT (requester, "fail to remove timer_id"); + priv->timeout_checker_id = 0; + ret = FALSE; + goto stop; + } + + for (walk = priv->request_ranges; walk; walk = g_list_next (walk)) { + GstWFDRTPRequestRange *range = (GstWFDRTPRequestRange *) walk->data; + + if (range) { + elapsed = g_timer_elapsed (priv->timer, NULL); + if (elapsed - range->request_time > (requester->timeout_ms / 1000)) { + GST_DEBUG_OBJECT (requester, "remove range for #%d~#%d", + range->start_seqnum, range->end_seqnum); + priv->request_ranges = g_list_remove (priv->request_ranges, range); + is_timeout = TRUE; + } + } + } + + if (is_timeout) { + GST_DEBUG_OBJECT (requester, "emit timeout signal"); + g_signal_emit (requester, gst_wfd_rtp_requester_signals[SIGNAL_REQUEST_TIMEOUT], 0); + } + +stop: + return ret; +} + +static GstWFDRTPRequestRange * +create_range (GstWFDRTPRequester *requester, guint16 start_seqnum, guint16 end_seqnum) +{ + GstWFDRTPRequestRange *range = NULL; + GstWFDRTPRequesterPrivate *priv; + + priv = GST_WFD_RTP_REQUESTER_GET_PRIVATE(requester); + + range = g_new0 (GstWFDRTPRequestRange, 1); + if (!range) { + GST_DEBUG_OBJECT (requester, "fail to create range for #%d~#%d", start_seqnum, end_seqnum); + return NULL; + } + + if (!priv->timer) + priv->timer = g_timer_new (); + + if (!priv->timeout_checker_id) { + priv->timeout_checker_id = g_timeout_add (requester->timeout_ms, + (GSourceFunc)check_timeout, (gpointer)requester); + GST_DEBUG_OBJECT (requester, "create timer(%d) for checking request timeout", priv->timeout_checker_id); + } + + range->start_seqnum = start_seqnum; + range->end_seqnum = end_seqnum; + range->request_packet_num = end_seqnum - start_seqnum + 0x0001; + range->retransmitted_packet_num = 0; + range->request_time = g_timer_elapsed (priv->timer, NULL); + + GST_DEBUG_OBJECT (requester, "create range for #%d~#%d at %.4f sec", + range->start_seqnum, range->end_seqnum, range->request_time); + + return range; +} + +static gint +find_range_by_seqnum (GstWFDRTPRequestRange * range, guint16 * seqnum) +{ + if (range->start_seqnum <= *seqnum && range->end_seqnum >= *seqnum) + return 0; + + return -1; +} + +static GstWFDRTPRequestRange * +find_range (GstWFDRTPRequester *requester, gconstpointer data, gconstpointer func) +{ + GstWFDRTPRequesterPrivate *priv; + GList *lranges; + + priv = GST_WFD_RTP_REQUESTER_GET_PRIVATE(requester); + + /* find and get stream */ + if ((lranges = g_list_find_custom (priv->request_ranges, data, (GCompareFunc) func))) + return (GstWFDRTPRequestRange *) lranges->data; + + return NULL; +} + +static void +remove_range (GstWFDRTPRequester *requester, guint16 seqnum) +{ + GstWFDRTPRequestRange *range; + + range = find_range (requester, &seqnum, (gpointer) find_range_by_seqnum); + if (!range) { + GST_DEBUG_OBJECT (requester, "fail to find range for #%d rtp pakcet", seqnum); + return; + } + + range->retransmitted_packet_num++; + + GST_DEBUG_OBJECT (requester, "found range for #%d [%d~%d, remain %d packets]", + seqnum, range->start_seqnum, range->end_seqnum, + range->request_packet_num - range->retransmitted_packet_num); + + if (range->retransmitted_packet_num == range->request_packet_num) { + GST_DEBUG_OBJECT (requester, "all requested rtp packets are arrived, remove range"); + requester->priv->request_ranges = g_list_remove(requester->priv->request_ranges, range); + } + + return; +} + +void +wfd_rtp_requester_perform_request (GstWFDRTPRequester *requester, guint16 expected_seqnum, guint16 received_seqnum) +{ + GstWFDRTPRequesterPrivate *priv; + GstFlowReturn ret =GST_FLOW_OK; + GstRTCPPacket rtcp_fb_packet; + GstBuffer *rtcp_fb_buf; + GstRTCPBuffer rtcp_buf = {NULL}; + GstWFDRTPRequestRange * range; + guint8 *fci_data; + guint16 pid, blp; + guint rtcp_packet_cnt = 0; + gint gap; + gint i; + + priv = GST_WFD_RTP_REQUESTER_GET_PRIVATE(requester); + + /* can't continue without gap */ + gap = received_seqnum - expected_seqnum; + if (G_UNLIKELY (gap<1)) + goto no_gap; + + pid = expected_seqnum; + +again: + /* create buffer for rtcp fb packets */ + rtcp_fb_buf = gst_rtcp_buffer_new(REQUESTER_MTU_SIZE); + if (!G_UNLIKELY(rtcp_fb_buf)) + goto fail_buf; + if (!gst_rtcp_buffer_map (rtcp_fb_buf, GST_MAP_READWRITE, &rtcp_buf)) + goto fail_buf; + + /* create rtcp fb packet */ + do { + if (!gst_rtcp_buffer_add_packet (&rtcp_buf, GST_RTCP_TYPE_RTPFB, + &rtcp_fb_packet)) { + if (rtcp_packet_cnt>0) + goto send_packets; + else { + gst_rtcp_buffer_unmap (&rtcp_buf); + goto fail_packet; + } + } + + /* set rtcp fb header : wfd use RTCPFB with Generick NACK */ + gst_rtcp_packet_fb_set_type (&rtcp_fb_packet, GST_RTCP_RTPFB_TYPE_NACK); + gst_rtcp_packet_fb_set_sender_ssrc (&rtcp_fb_packet, 0); + gst_rtcp_packet_fb_set_media_ssrc (&rtcp_fb_packet, 0); + + /* set rtcp fb fci(feedback control information) : 32bits */ + if (!gst_rtcp_packet_fb_set_fci_length (&rtcp_fb_packet, 2)) { + GST_DEBUG_OBJECT (requester, "fail to set FCI length to RTCP FB packet"); + gst_rtcp_packet_remove (&rtcp_fb_packet); + return; + } + + fci_data = gst_rtcp_packet_fb_get_fci (&rtcp_fb_packet) - + ((gst_rtcp_packet_fb_get_fci_length (&rtcp_fb_packet) - 2) * 4); + + /* set pid */ + GST_WRITE_UINT16_BE (fci_data, pid); + pid += 0x0011; + gap--; + + /* set blp */ + blp = 0x0000; + for (i=0; i<16 && gap>0; i++) { + blp += (0x0001 << i); + gap--; + } + GST_WRITE_UINT16_BE (fci_data + 2, blp); + + rtcp_packet_cnt++; + + GST_DEBUG_OBJECT (requester, "%d RTCP FB packet : pid : %x, blp : %x", rtcp_packet_cnt, pid-0x0011, blp); + }while (gap>0); + +send_packets: + /* end rtcp fb buffer */ + gst_rtcp_buffer_unmap (&rtcp_buf); + + /* Note : Should be crate range before requesting */ + if (requester->timeout_ms > 0) { + range = create_range (requester, expected_seqnum, received_seqnum - 0x0001); + if (range) + priv->request_ranges = g_list_append (priv->request_ranges, range); + } + + ret = gst_pad_push(requester->rtcp_src, rtcp_fb_buf); + if (ret != GST_FLOW_OK) + GST_WARNING_OBJECT(requester, "fail to pad push RTCP FB buffer"); + + if (gap>0) + goto again; + + return; + + /* ERRORS */ +no_gap: + { + GST_DEBUG_OBJECT (requester, "there is no gap, don't need to make the RTSP FB packet"); + return; + } +fail_buf: + { + GST_DEBUG_OBJECT (requester, "fail to make RTSP FB buffer"); + return; + } +fail_packet: + { + GST_DEBUG_OBJECT (requester, "fail to make RTSP FB packet"); + return; + } +} + +void +wfd_rtp_requester_cancel_request (GstWFDRTPRequester *requester, guint16 seqnum) +{ + /* need to fill up */ + GST_DEBUG_OBJECT (requester, ""); +} + +/* chain function + * this function does the actual processing + */ +static GstFlowReturn +gst_wfd_rtp_requester_chain (GstPad * pad, GstObject *parent, GstBuffer * buf) +{ + GstWFDRTPRequester *requester; + GstWFDRTPRequesterPrivate *priv; + guint16 seqnum; + guint8 pt; + guint32 ssrc; + GstFlowReturn ret = GST_FLOW_OK; + GstRTPBuffer rtp_buf = { NULL }; + + requester = GST_WFD_RTP_REQUESTER (gst_pad_get_parent (pad)); + priv = GST_WFD_RTP_REQUESTER_GET_PRIVATE(requester); + + if (priv->flushing) + goto drop_buffer; + + if (G_UNLIKELY (!gst_rtp_buffer_map( buf, GST_MAP_READ, &rtp_buf) )) + goto invalid_buffer; + + /* check ssrc */ + ssrc = gst_rtp_buffer_get_ssrc (&rtp_buf); + if (G_LIKELY(!requester->ssrc)) { + GST_DEBUG_OBJECT(requester, "set ssrc as %x using first rtp packet", ssrc); + requester->ssrc = ssrc; + } else if (G_LIKELY (requester->ssrc != ssrc)) { + //goto invalid_ssrc; + GST_ERROR_OBJECT(requester, "ssrc is changed from %x to %x", requester->ssrc, ssrc); + requester->ssrc = ssrc; + } + + + /* check pt : pt should always 33 for MP2T-ES */ + pt = gst_rtp_buffer_get_payload_type (&rtp_buf); + if (G_LIKELY (requester->pt != pt)) { + if (G_LIKELY(!requester->pt)) { + requester->pt = pt; + } else { + gst_rtp_buffer_unmap(&rtp_buf); + goto invalid_pt; + } + } + + seqnum = gst_rtp_buffer_get_seq (&rtp_buf); + + /* now check against our expected seqnum */ + if (G_LIKELY (priv->next_in_seqnum != GST_CLOCK_TIME_NONE)) { + gint gap; + + gap = gst_rtp_buffer_compare_seqnum (priv->next_in_seqnum, seqnum); + if (G_UNLIKELY (gap != 0)) { + GST_ERROR_OBJECT (requester, "expected #%d, got #%d, gap of %d", (guint16)priv->next_in_seqnum, seqnum, gap); + + if (requester->do_request) { + /* priv->next_in_seqnum >= seqnum, this packet is too late or the + * sender might have been restarted with different seqnum. */ + if (G_UNLIKELY (gap < 0)) { + GST_DEBUG_OBJECT (requester, "#%d is late", seqnum); + wfd_rtp_requester_cancel_request(requester, seqnum); + goto skip; + } + /* priv->next_in_seqnum < seqnum, this is a new packet */ + else if (G_UNLIKELY (gap > REQUESTER_MAX_DROPOUT)) { + GST_DEBUG_OBJECT (requester, "reset: too many dropped packets %d", + gap); + } else { + GST_DEBUG_OBJECT (requester, "tolerable gap"); + wfd_rtp_requester_perform_request(requester, priv->next_in_seqnum, seqnum); + } + } + } + } + priv->next_in_seqnum = (seqnum + 1) & 0xffff; + +skip: + gst_rtp_buffer_unmap(&rtp_buf); + /* just push out the incoming buffer without touching it */ + ret = gst_pad_push (requester->rtp_src, buf); + if (ret != GST_FLOW_OK) + GST_ERROR_OBJECT (requester, "fail to pad push..reason %s", gst_flow_get_name(ret)); + + gst_object_unref (requester); + + return ret; + + /* ERRORS */ +drop_buffer: + { + GST_ERROR_OBJECT (requester, + "requeseter is flushing, drop incomming buffers.."); + gst_buffer_unref (buf); + gst_object_unref (requester); + return GST_FLOW_OK; + } +invalid_buffer: + { + /* this is not fatal but should be filtered earlier */ + GST_ELEMENT_WARNING (requester, STREAM, DECODE, (NULL), + ("Received invalid RTP payload, dropping")); + gst_buffer_unref (buf); + gst_object_unref (requester); + return GST_FLOW_OK; + } +invalid_ssrc: + { + /* this is not fatal but should be filtered earlier */ + GST_ELEMENT_WARNING (requester, STREAM, DECODE, (NULL), + ("ssrc of this rtp packet is differtent from before. dropping")); + gst_buffer_unref (buf); + gst_object_unref (requester); + return GST_FLOW_OK; + } +invalid_pt: + { + /* this is not fatal but should be filtered earlier */ + GST_ELEMENT_WARNING (requester, STREAM, DECODE, (NULL), + ("pt of this rtp packet is differtent from before. dropping")); + gst_buffer_unref (buf); + gst_object_unref (requester); + return GST_FLOW_OK; + } +} + +GstBuffer* +wfd_requester_handle_retransmitted_rtp (GstWFDRTPRequester *requester, GstBuffer *ret_rtp_buf) +{ + GstBuffer *rtp_buf; + guint16 seqnum; + guint8 *buf_data; + guint buf_size; + guint8 *payload; + guint payload_len, header_len; + GstMapInfo ret_buf_mapinfo; + GstRTPBuffer rtp_ret_buf = {NULL}; + GstMapInfo res_buf_mapinfo; + GstRTPBuffer rtp_res_buffer = {NULL}; + + if (!gst_rtp_buffer_map (ret_rtp_buf, GST_MAP_READ, &rtp_ret_buf)) { + GST_WARNING_OBJECT (requester, "Could not map rtp buffer"); + return NULL; + } + + gst_buffer_map (ret_rtp_buf, &ret_buf_mapinfo, GST_MAP_READ); + buf_data = ret_buf_mapinfo.data; + buf_size = ret_buf_mapinfo.size; + payload = gst_rtp_buffer_get_payload(&rtp_ret_buf); + payload_len = gst_rtp_buffer_get_payload_len(&rtp_ret_buf); + header_len = gst_rtp_buffer_get_header_len(&rtp_ret_buf); + + gst_rtp_buffer_unmap (&rtp_ret_buf); + + rtp_buf = gst_buffer_new_and_alloc(buf_size - 2); + if (!rtp_buf) { + GST_WARNING_OBJECT(requester, "fail to alloc for rtp buffer"); + gst_buffer_unmap (ret_rtp_buf, &ret_buf_mapinfo); + return NULL; + } + gst_buffer_map (rtp_buf, &res_buf_mapinfo, GST_MAP_READ | GST_MAP_WRITE); + + /* copy rtp header */ + memcpy(res_buf_mapinfo.data, buf_data, header_len); + /* copy rtp payload */ + memcpy(res_buf_mapinfo.data+header_len, payload+2, payload_len-2); + + /* set seqnum to original */ + if (!gst_rtp_buffer_map (rtp_buf, GST_MAP_READWRITE, &rtp_res_buffer) ) { + GST_WARNING_OBJECT (requester, "Could not map rtp result buffer"); + gst_buffer_unmap (ret_rtp_buf, &ret_buf_mapinfo); + gst_buffer_unmap (rtp_buf, &res_buf_mapinfo); + return NULL; + } + seqnum = GST_READ_UINT16_BE (payload); + gst_rtp_buffer_set_seq(&rtp_res_buffer, seqnum); + gst_rtp_buffer_unmap (&rtp_res_buffer); + + GST_DEBUG_OBJECT (requester, "restored packet #%d", seqnum); + + if (requester->timeout_ms>0) + remove_range (requester, seqnum); + + gst_buffer_unmap (ret_rtp_buf, &ret_buf_mapinfo); + gst_buffer_unmap (rtp_buf, &res_buf_mapinfo); + + return rtp_buf; +} + +static GstFlowReturn +gst_wfd_rtp_requester_chain_retransmitted_rtp (GstPad * pad, GstObject *parent, GstBuffer * buf) +{ + GstWFDRTPRequester *requester; + GstWFDRTPRequesterPrivate *priv; + GstFlowReturn ret = GST_FLOW_OK; + guint16 seqnum; + guint8 pt; + GstBuffer *outbuf; + GstRTPBuffer rtp_buf = {NULL}; + + requester = GST_WFD_RTP_REQUESTER (gst_pad_get_parent (pad)); + priv = GST_WFD_RTP_REQUESTER_GET_PRIVATE(requester); + + if (!requester->do_request) + goto skip_buffer; + + if (priv->flushing) + goto drop_buffer; + + if (G_UNLIKELY (!gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp_buf))) + goto invalid_buffer; + + pt = gst_rtp_buffer_get_payload_type (&rtp_buf); + if (G_LIKELY (requester->pt != pt)) { + gst_rtp_buffer_unmap (&rtp_buf); + goto invalid_pt; + } + + seqnum = gst_rtp_buffer_get_seq (&rtp_buf); + gst_rtp_buffer_unmap (&rtp_buf); + + GST_DEBUG_OBJECT (requester, "Received packet #%d", seqnum); + + outbuf = wfd_requester_handle_retransmitted_rtp(requester, buf); + if (!outbuf) { + GST_DEBUG_OBJECT (requester, "fail to handle retransmitted rtp packet..."); + return GST_FLOW_OK; + } + + ret = gst_pad_push (requester->rtp_src, outbuf); + if (ret retransmitted_rtp_sink != NULL) + goto exists; + + GST_LOG_OBJECT (requester, "Creating new pad for retreansmitted RTP packets"); + + requester->retransmitted_rtp_sink = + gst_pad_new_from_static_template (&retransmitted_rtp_sink_template, + "retransmitted_rtp_sink"); + gst_pad_set_chain_function (requester->retransmitted_rtp_sink, + gst_wfd_rtp_requester_chain_retransmitted_rtp); + gst_pad_set_event_function (requester->retransmitted_rtp_sink, + (GstPadEventFunction) gst_wfd_rtp_requester_sink_event_retransmitted_rtp); + gst_pad_use_fixed_caps (requester->retransmitted_rtp_sink); + gst_pad_set_active (requester->retransmitted_rtp_sink, TRUE); + gst_element_add_pad (GST_ELEMENT_CAST (requester), + requester->retransmitted_rtp_sink); + + GST_DEBUG_OBJECT (requester, "creating RTCP src pad for RTCP FB packets"); + requester->rtcp_src = + gst_pad_new_from_static_template (&rtcp_src_template, + "rtcp_src"); + gst_pad_set_event_function (requester->rtcp_src, + (GstPadEventFunction) gst_wfd_rtp_requester_src_event_rtcp); + gst_pad_use_fixed_caps (requester->rtcp_src); + gst_pad_set_active (requester->rtcp_src, TRUE); + gst_element_add_pad (GST_ELEMENT_CAST (requester), requester->rtcp_src); + + GST_WFD_RTP_REQUESTER_UNLOCK (requester); + + return requester->retransmitted_rtp_sink; + +/* ERRORS */ +wrong_template: + { + GST_WFD_RTP_REQUESTER_UNLOCK (requester); + g_warning ("wfdrtprequester: this is not our template"); + return NULL; + } +exists: + { + GST_WFD_RTP_REQUESTER_UNLOCK (requester); + g_warning ("wfdrtprequester: pad already requested"); + return NULL; + } +} + +static void +gst_wfd_rtp_requester_release_pad (GstElement * element, GstPad * pad) +{ + GstWFDRTPRequester *requester; + + g_return_if_fail (GST_IS_WFD_RTP_REQUESTER (element)); + g_return_if_fail (GST_IS_PAD (pad)); + + requester = GST_WFD_RTP_REQUESTER (element); + + GST_DEBUG_OBJECT (element, "releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad)); + + GST_WFD_RTP_REQUESTER_LOCK (requester); + + if (requester->retransmitted_rtp_sink == pad) { + /* deactivate from source to sink */ + gst_pad_set_active (requester->rtcp_src, FALSE); + gst_pad_set_active (requester->retransmitted_rtp_sink, FALSE); + + /* remove pads */ + GST_DEBUG_OBJECT (requester, "removing retransmitted RTP sink pad"); + gst_element_remove_pad (GST_ELEMENT_CAST (requester), + requester->retransmitted_rtp_sink); + requester->retransmitted_rtp_sink = NULL; + + GST_DEBUG_OBJECT (requester, "removing RTCP src pad"); + gst_element_remove_pad (GST_ELEMENT_CAST (requester), + requester->rtcp_src); + requester->rtcp_src = NULL; + } else + goto wrong_pad; + + GST_WFD_RTP_REQUESTER_UNLOCK (requester); + + return; + + /* ERRORS */ +wrong_pad: + { + GST_WFD_RTP_REQUESTER_UNLOCK (requester); + g_warning ("wfdrtprequester: asked to release an unknown pad"); + return; + } +} + + +/* entry point to initialize the plug-in + * initialize the plug-in itself + * register the element factories and other features + */ +static gboolean +gst_wfd_rtp_requester_plugin_init (GstPlugin *plugin) +{ + if (!gst_element_register (plugin, "wfdrtprequester", GST_RANK_PRIMARY, gst_wfd_rtp_requester_get_type())) { + return FALSE; + } + return TRUE; +} + +/* gstreamer looks for this structure to register plugins + * + * exchange the string 'Template plugin' with your plugin description + */ +GST_PLUGIN_DEFINE ( + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + wfdrtprequester, + "WFD RTP Requester plugin", + gst_wfd_rtp_requester_plugin_init, + VERSION, + "LGPL", + "GStreamer", + "http://gstreamer.net/" +) + diff --git a/wfdrtspsrc/src/gstwfdrtprequester.h b/wfdrtspsrc/src/gstwfdrtprequester.h new file mode 100755 index 0000000..e5ae8d3 --- /dev/null +++ b/wfdrtspsrc/src/gstwfdrtprequester.h @@ -0,0 +1,102 @@ +/* + * wfdrtprequester + * + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * 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. + */ + + +#ifndef __GST_WFD_RTP_REQUESTER_H__ +#define __GST_WFD_RTP_REQUESTER_H__ + +#include + +G_BEGIN_DECLS + +/* #defines don't like whitespacey bits */ +#define GST_TYPE_WFD_RTP_REQUESTER \ + (gst_wfd_rtp_requester_get_type()) +#define GST_WFD_RTP_REQUESTER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WFD_RTP_REQUESTER,GstWFDRTPRequester)) +#define GST_WFD_RTP_REQUESTER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WFD_RTP_REQUESTER,GstWFDRTPRequesterClass)) +#define GST_IS_WFD_RTP_REQUESTER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WFD_RTP_REQUESTER)) +#define GST_IS_WFD_RTP_REQUESTER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WFD_RTP_REQUESTER)) +#define GST_WFD_RTP_REQUESTER_CAST(obj) ((GstWFDRTPRequester *)(obj)) + +typedef struct _GstWFDRTPRequester GstWFDRTPRequester; +typedef struct _GstWFDRTPRequesterClass GstWFDRTPRequesterClass; +typedef struct _GstWFDRTPRequesterPrivate GstWFDRTPRequesterPrivate; + +struct _GstWFDRTPRequester +{ + GstElement element; + + GstPad *rtp_sink, *rtp_src; + GstPad *rtcp_src, *retransmitted_rtp_sink; + + /* properties */ + gboolean do_request; + guint32 ssrc; + guint8 pt; + guint timeout_ms; + guint64 timeout_ns; + + GstWFDRTPRequesterPrivate *priv; +}; + +struct _GstWFDRTPRequesterClass +{ + GstElementClass parent_class; + + /* signals */ + void (*request_timeout) (GstWFDRTPRequester *requester); +}; + +GType gst_wfd_rtp_requester_get_type (void); + +G_END_DECLS + +#endif /* __GST_WFD_RTP_REQUESTER_H__ */ + diff --git a/wfdrtspsrc/src/gstwfdrtspext.c b/wfdrtspsrc/src/gstwfdrtspext.c new file mode 100755 index 0000000..94bb5fc --- /dev/null +++ b/wfdrtspsrc/src/gstwfdrtspext.c @@ -0,0 +1,273 @@ +/* + * wfdrtspext + * + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * 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. + */ + + +#include "gstwfdrtspext.h" + +GST_DEBUG_CATEGORY_STATIC (wfdrtspext_debug); +#define GST_CAT_DEFAULT (wfdrtspext_debug) + +static GList *extensions; + +static gboolean +gst_wfd_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, "GstWFDRTSPExtension")) + 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_wfd_rtsp_ext_list_init (void) +{ + GST_DEBUG_CATEGORY_INIT (wfdrtspext_debug, "wfdrtspext", 0, "WFD RTSP extension"); + + /* get a list of all extensions */ + extensions = gst_registry_feature_filter (gst_registry_get (), + (GstPluginFeatureFilter) gst_wfd_rtsp_ext_list_filter, FALSE, NULL); +} + +GstWFDRTSPExtensionList * +gst_wfd_rtsp_ext_list_get (void) +{ + GstWFDRTSPExtensionList *result; + GList *walk; + + result = g_new0 (GstWFDRTSPExtensionList, 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_wfd_rtsp_ext_list_free (GstWFDRTSPExtensionList * 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_wfd_rtsp_ext_list_detect_server (GstWFDRTSPExtensionList * 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_wfd_rtsp_ext_list_before_send (GstWFDRTSPExtensionList * 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_wfd_rtsp_ext_list_after_send (GstWFDRTSPExtensionList * 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_wfd_rtsp_ext_list_parse_sdp (GstWFDRTSPExtensionList * 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_wfd_rtsp_ext_list_setup_media (GstWFDRTSPExtensionList * 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_wfd_rtsp_ext_list_configure_stream (GstWFDRTSPExtensionList * 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_wfd_rtsp_ext_list_get_transports (GstWFDRTSPExtensionList * 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_wfd_rtsp_ext_list_stream_select (GstWFDRTSPExtensionList * 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_wfd_rtsp_ext_list_connect (GstWFDRTSPExtensionList * 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_wfd_rtsp_ext_list_receive_request (GstWFDRTSPExtensionList * 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/wfdrtspsrc/src/gstwfdrtspext.h b/wfdrtspsrc/src/gstwfdrtspext.h new file mode 100755 index 0000000..f95b69e --- /dev/null +++ b/wfdrtspsrc/src/gstwfdrtspext.h @@ -0,0 +1,88 @@ +/* + * wfdrtspext + * + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * 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. + */ + + +#ifndef __GST_WFD_RTSP_EXT_H__ +#define __GST_WFD_RTSP_EXT_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _GstWFDRTSPExtensionList GstWFDRTSPExtensionList; + +struct _GstWFDRTSPExtensionList +{ + GList *extensions; +}; + +void gst_wfd_rtsp_ext_list_init (void); + +GstWFDRTSPExtensionList * gst_wfd_rtsp_ext_list_get (void); +void gst_wfd_rtsp_ext_list_free (GstWFDRTSPExtensionList *ext); + +gboolean gst_wfd_rtsp_ext_list_detect_server (GstWFDRTSPExtensionList *ext, GstRTSPMessage *resp); + +GstRTSPResult gst_wfd_rtsp_ext_list_before_send (GstWFDRTSPExtensionList *ext, GstRTSPMessage *req); +GstRTSPResult gst_wfd_rtsp_ext_list_after_send (GstWFDRTSPExtensionList *ext, GstRTSPMessage *req, + GstRTSPMessage *resp); +GstRTSPResult gst_wfd_rtsp_ext_list_parse_sdp (GstWFDRTSPExtensionList *ext, GstSDPMessage *sdp, + GstStructure *s); +GstRTSPResult gst_wfd_rtsp_ext_list_setup_media (GstWFDRTSPExtensionList *ext, GstSDPMedia *media); +gboolean gst_wfd_rtsp_ext_list_configure_stream (GstWFDRTSPExtensionList *ext, GstCaps *caps); +GstRTSPResult gst_wfd_rtsp_ext_list_get_transports (GstWFDRTSPExtensionList *ext, GstRTSPLowerTrans protocols, + gchar **transport); +GstRTSPResult gst_wfd_rtsp_ext_list_stream_select (GstWFDRTSPExtensionList *ext, GstRTSPUrl *url); + +void gst_wfd_rtsp_ext_list_connect (GstWFDRTSPExtensionList *ext, + const gchar *detailed_signal, GCallback c_handler, + gpointer data); +GstRTSPResult gst_wfd_rtsp_ext_list_receive_request (GstWFDRTSPExtensionList *ext, GstRTSPMessage *req); + +G_END_DECLS + +#endif /* __GST_RTSP_EXT_H__ */ diff --git a/wfdrtspsrc/src/gstwfdrtspsrc.c b/wfdrtspsrc/src/gstwfdrtspsrc.c new file mode 100755 index 0000000..916dfac --- /dev/null +++ b/wfdrtspsrc/src/gstwfdrtspsrc.c @@ -0,0 +1,4645 @@ +/* + * wfdrtspsrc + * + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * 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. + */ + +/** +* SECTION:element-wfdrtspsrc +* +* Makes a connection to an RTSP server and read the data. +* Device recognition is through wifi direct. +* wfdrtspsrc strictly follows Wifi display specification. +* +* RTSP supports transport over TCP or UDP in unicast or multicast mode. By +* default wfdrtspsrc 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 #GstWFDRTSPSrc:protocols property. +* +* wfdrtspsrc currently understands WFD capability negotiation messages +* +* wfdrtspsrc 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. +* +* wfdrtspsrc acts like a live source and will therefore only generate data in the +* PLAYING state. +* +* +* Example launch line +* |[ +* gst-launch wfdrtspsrc location=rtsp://some.server/url ! fakesink +* ]| Establish a connection to an RTSP server and send the raw RTP packets to a +* fakesink. +* +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gstwfdrtspsrc.h" + +#ifdef G_OS_WIN32 +#include +#endif + +GST_DEBUG_CATEGORY_STATIC (wfdrtspsrc_debug); +#define GST_CAT_DEFAULT (wfdrtspsrc_debug) + +static GstStaticPadTemplate gst_wfdrtspsrc_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("application/x-rtp, " + "payload = (int) 33")); + +/* signals and args */ +enum +{ + SIGNAL_UPDATE_MEDIA_INFO, + LAST_SIGNAL +}; + +enum _GstWfdRtspSrcBufferMode +{ + BUFFER_MODE_NONE, + BUFFER_MODE_SLAVE, + BUFFER_MODE_BUFFER, + BUFFER_MODE_AUTO +}; + +#define _SET_FRAMERATE_TO_CAPS 1 + + +#define GST_TYPE_WFD_RTSP_NAT_METHOD (gst_wfd_rtsp_nat_method_get_type()) +static GType +gst_wfd_rtsp_nat_method_get_type (void) +{ + static GType wfd_rtsp_nat_method_type = 0; + static const GEnumValue wfd_rtsp_nat_method[] = { + {GST_WFD_RTSP_NAT_NONE, "None", "none"}, + {GST_WFD_RTSP_NAT_DUMMY, "Send Dummy packets", "dummy"}, + {0, NULL, NULL}, + }; + + if (!wfd_rtsp_nat_method_type) { + wfd_rtsp_nat_method_type = + g_enum_register_static ("GstWFDRTSPNatMethod", wfd_rtsp_nat_method); + } + return wfd_rtsp_nat_method_type; +} + +/* properties default values */ +#define DEFAULT_LOCATION NULL +#define DEFAULT_DEBUG FALSE +#define DEFAULT_RETRY 20 +#define DEFAULT_TCP_TIMEOUT 20000000 +#define DEFAULT_NAT_METHOD GST_WFD_RTSP_NAT_DUMMY +#define DEFAULT_PROXY NULL +#define DEFAULT_RTP_BLOCKSIZE 0 +#define DEFAULT_USER_ID NULL +#define DEFAULT_USER_PW NULL +#define DEFAULT_PORT_RANGE NULL +#define DEFAULT_USER_AGENT "TIZEN-WFD-SINK" +#define DEFAULT_DO_RTCP TRUE +#define DEFAULT_LATENCY_MS 2000 +#define DEFAULT_UDP_BUFFER_SIZE 0x80000 +#define DEFAULT_UDP_TIMEOUT 5000000 + +enum +{ + PROP_0, + PROP_LOCATION, + PROP_DEBUG, + PROP_RETRY, + PROP_TCP_TIMEOUT, + PROP_NAT_METHOD, + PROP_PROXY, + PROP_RTP_BLOCKSIZE, + PROP_USER_ID, + PROP_USER_PW, + PROP_USER_AGENT, + PROP_AUDIO_PARAM, + PROP_VIDEO_PARAM, + PROP_HDCP_PARAM, + PROP_DO_RTCP, + PROP_LATENCY, + PROP_UDP_BUFFER_SIZE, + PROP_UDP_TIMEOUT, + PROP_ENABLE_PAD_PROBE, + PROP_LAST +}; + +#define gst_wfdrtspsrc_parent_class parent_class + +/* commands we send to out loop to notify it of events */ +#define CMD_OPEN 0 +#define CMD_PLAY 1 +#define CMD_PAUSE 2 +#define CMD_CLOSE 3 +#define CMD_WAIT 4 +#define CMD_LOOP 5 + +#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 + +/* object */ +static void gst_wfdrtspsrc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_wfdrtspsrc_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_wfdrtspsrc_dispose (GObject * object); +static void gst_wfdrtspsrc_finalize (GObject * object); + +/* element */ +static GstStateChangeReturn gst_wfdrtspsrc_change_state (GstElement * element, + GstStateChange transition); +static gboolean gst_wfdrtspsrc_send_event (GstElement * element, GstEvent * event); + +/* bin */ +static void gst_wfdrtspsrc_handle_message (GstBin * bin, GstMessage * message); + +static void gst_wfdrtspsrc_loop_send_cmd (GstWFDRTSPSrc * src, gint cmd); + +/* fundemental functions */ +static GstRTSPResult gst_wfdrtspsrc_open (GstWFDRTSPSrc * src); +static gboolean gst_wfdrtspsrc_setup (GstWFDRTSPSrc * src); +static GstRTSPResult gst_wfdrtspsrc_play (GstWFDRTSPSrc * src); +static GstRTSPResult gst_wfdrtspsrc_pause (GstWFDRTSPSrc * src); +static GstRTSPResult gst_wfdrtspsrc_close (GstWFDRTSPSrc * src, gboolean only_close); + +static gboolean gst_wfdrtspsrc_set_proxy (GstWFDRTSPSrc * rtsp, const gchar * proxy); +static void gst_wfdrtspsrc_set_tcp_timeout (GstWFDRTSPSrc * src, guint64 timeout); + + +static gboolean gst_wfdrtspsrc_setup_auth (GstWFDRTSPSrc * src, + GstRTSPMessage * response); + +static GstRTSPResult gst_wfdrtspsrc_send_cb (GstRTSPExtension * ext, + GstRTSPMessage * request, GstRTSPMessage * response, GstWFDRTSPSrc * src); + + +static void gst_wfdrtspsrc_uri_handler_init (gpointer g_iface, + gpointer iface_data); +static gboolean gst_wfdrtspsrc_uri_set_uri (GstURIHandler * handler, + const gchar * uri, GError **error); + +static gboolean gst_wfdrtspsrc_loop (GstWFDRTSPSrc * src); +static gboolean gst_wfdrtspsrc_stream_push_event (WFDRTSPManager * manager, + GstEvent * event, gboolean source); +static gboolean gst_wfdrtspsrc_push_event (GstWFDRTSPSrc * src, GstEvent * event, + gboolean source); + + +static GstRTSPResult +gst_wfdrtspsrc_send (GstWFDRTSPSrc * src, GstRTSPConnection * conn, + GstRTSPMessage * request, GstRTSPMessage * response, + GstRTSPStatusCode * code); + +static gboolean gst_wfdrtspsrc_parse_methods (GstWFDRTSPSrc * src, GstRTSPMessage * response); + +static GstRTSPResult gst_wfdrtspsrc_send_keep_alive (GstWFDRTSPSrc * src); + +static void gst_wfdrtspsrc_connection_flush (GstWFDRTSPSrc * src, gboolean flush); + +static GstRTSPResult gst_wfdrtspsrc_get_video_parameter(GstWFDRTSPSrc * src, WFDMessage *msg); +static GstRTSPResult gst_wfdrtspsrc_get_audio_parameter(GstWFDRTSPSrc * src, WFDMessage *msg); + +static gboolean +gst_wfdrtspsrc_handle_src_event (GstPad * pad, GstObject *parent, GstEvent * event); +static gboolean +gst_wfdrtspsrc_handle_src_query(GstPad * pad, GstObject *parent, GstQuery * query); + + + +static guint gst_wfdrtspsrc_signals[LAST_SIGNAL] = { 0 }; + +static void +_do_init (GType wfdrtspsrc_type) +{ + static const GInterfaceInfo urihandler_info = { + gst_wfdrtspsrc_uri_handler_init, + NULL, + NULL + }; + + GST_DEBUG_CATEGORY_INIT (wfdrtspsrc_debug, "wfdrtspsrc", 0, "WFD RTSP src"); + + g_type_add_interface_static (wfdrtspsrc_type, GST_TYPE_URI_HANDLER, + &urihandler_info); +} + +G_DEFINE_TYPE_WITH_CODE (GstWFDRTSPSrc, gst_wfdrtspsrc, GST_TYPE_BIN, _do_init(g_define_type_id)) + +static void +gst_wfdrtspsrc_class_init (GstWFDRTSPSrcClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBinClass *gstbin_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbin_class = (GstBinClass *) klass; + + gobject_class->set_property = gst_wfdrtspsrc_set_property; + gobject_class->get_property = gst_wfdrtspsrc_get_property; + gobject_class->dispose = gst_wfdrtspsrc_dispose; + gobject_class->finalize = gst_wfdrtspsrc_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_DEBUG, + g_param_spec_boolean ("debug", "Debug", + "Dump request and response messages to stdout", + DEFAULT_DEBUG, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + 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_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_NAT_METHOD, + g_param_spec_enum ("nat-method", "NAT Method", + "Method to use for traversing firewalls and NAT", + GST_TYPE_WFD_RTSP_NAT_METHOD, DEFAULT_NAT_METHOD, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + 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)); + + 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)); + + g_object_class_install_property (gobject_class, PROP_USER_AGENT, + g_param_spec_string ("user-agent", "User Agent", + "User agent specified string", DEFAULT_USER_AGENT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_AUDIO_PARAM, + g_param_spec_boxed ("audio-param", "audio parameters", + "A GstStructure specifies the mapping for audio parameters", + GST_TYPE_STRUCTURE, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_VIDEO_PARAM, + g_param_spec_boxed ("video-param", "video parameters", + "A GstStructure specifies the mapping for video parameters", + GST_TYPE_STRUCTURE, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_HDCP_PARAM, + g_param_spec_boxed ("hdcp-param", "HDCP parameters", + "A GstStructure specifies the mapping for HDCP parameters", + GST_TYPE_STRUCTURE, G_PARAM_READWRITE)); + + 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)); + + 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_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)); + + g_object_class_install_property (gobject_class, PROP_UDP_TIMEOUT, + g_param_spec_uint64 ("timeout", "Timeout", + "Fail after timeout microseconds on UDP connections (0 = disabled)", + 0, G_MAXUINT64, DEFAULT_UDP_TIMEOUT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_ENABLE_PAD_PROBE, + g_param_spec_boolean ("enable-pad-probe", "Enable Pad Probe", + "Enable pad probe for debugging", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gst_wfdrtspsrc_signals[SIGNAL_UPDATE_MEDIA_INFO] = + g_signal_new ("receive-M4-request", G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstWFDRTSPSrcClass, update_media_info), + NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_STRUCTURE); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_wfdrtspsrc_src_template)); + + gst_element_class_set_details_simple (gstelement_class, "Wi-Fi Display source element", + "Source/Network", + "Receive data over the Wi-Fi Direct network via RTSP", + "YeJin Cho "); + + gstelement_class->send_event = gst_wfdrtspsrc_send_event; + gstelement_class->change_state = gst_wfdrtspsrc_change_state; + + gstbin_class->handle_message = gst_wfdrtspsrc_handle_message; + + gst_wfd_rtsp_ext_list_init (); +} + +static GstStructure * +gst_wfd_rtsp_set_default_audio_param () +{ + GstStructure *param = NULL; + param = gst_structure_new ("audio_param", + "audio_codec", G_TYPE_UINT, 0x3, + "audio_latency", G_TYPE_UINT, 0x0, + "audio_channels", G_TYPE_UINT, 0x3, + "audio_sampling_frequency", G_TYPE_UINT, 0x1, + NULL); + + return param; +} + +static GstStructure * +gst_wfd_rtsp_set_default_video_param () +{ + GstStructure *param = NULL; + param = gst_structure_new ("video_param", + "video_codec", G_TYPE_UINT, 0x1, + "video_native_resolution", G_TYPE_UINT, 0x20, + "video_cea_support", G_TYPE_UINT, 0x194ab, + "video_vesa_support", G_TYPE_UINT, 0x15555555, + "video_hh_support", G_TYPE_UINT, 0x555, + "video_profile", G_TYPE_UINT, 0x1, + "video_level", G_TYPE_UINT, 0x2, + "video_latency", G_TYPE_UINT, 0x0, + "video_vertical_resolution", G_TYPE_INT, 1200, + "video_horizontal_resolution", G_TYPE_INT, 1920, + "video_minimum_slicing", G_TYPE_INT, 0, + "video_slice_enc_param", G_TYPE_INT, 200, + "video_framerate_control_support", G_TYPE_INT, 11, + NULL); + + return param; +} + +static void +gst_wfdrtspsrc_init (GstWFDRTSPSrc * src) +{ + GstPadTemplate *template = NULL; + GstPad * outpad = NULL; + + +#ifdef G_OS_WIN32 + WSADATA wsa_data; + + if (WSAStartup (MAKEWORD (2, 2), &wsa_data) != 0) { + GST_ERROR_OBJECT (src, "WSAStartup failed: 0x%08x", WSAGetLastError ()); + } +#endif + + src->conninfo.location = g_strdup (DEFAULT_LOCATION); + src->conninfo.url_str = NULL; + src->debug = DEFAULT_DEBUG; + src->retry = DEFAULT_RETRY; + gst_wfdrtspsrc_set_tcp_timeout (src, DEFAULT_TCP_TIMEOUT); + src->nat_method = DEFAULT_NAT_METHOD; + gst_wfdrtspsrc_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->user_agent = g_strdup (DEFAULT_USER_AGENT); + src->ssr_timeout.tv_sec = 0; + src->ssr_timeout.tv_usec = 0; + src->is_paused = TRUE; + src->do_stop = FALSE; + src->audio_param = NULL; + src->video_param = NULL; + src->hdcp_param = NULL; + + src->audio_param = gst_wfd_rtsp_set_default_audio_param (); + src->video_param = gst_wfd_rtsp_set_default_video_param (); + + /* get a list of all extensions */ + src->extensions = gst_wfd_rtsp_ext_list_get (); + + /* connect to send signal */ + gst_wfd_rtsp_ext_list_connect (src->extensions, "send", + (GCallback) gst_wfdrtspsrc_send_cb, src); + + /* init lock */ + src->task_rec_lock = g_new (GRecMutex, 1); + g_rec_mutex_init (src->task_rec_lock); + + /* create manager */ + src->manager = wfd_rtsp_manager_new (GST_ELEMENT_CAST(src)); + + /* construct wfdrtspsrc */ + src->manager->session = gst_element_factory_make ("rtpsession", "wfdrtspsrc_session"); + if (G_UNLIKELY (src->manager->session == NULL)) { + GST_ERROR_OBJECT (src, "could not create gstrtpsession element"); + return; + } + + GST_BIN_CLASS (parent_class)->add_element (GST_BIN_CAST (src), + src->manager->session); + +#if 0 + src->manager->requester = gst_element_factory_make ("wfdrtprequester", "wfdrtspsrc_requester"); + if (G_UNLIKELY (src->manager->requester == NULL)) { + GST_ERROR_OBJECT (src, "could not create wfdrtprequester element"); + return; + } + + GST_BIN_CLASS (parent_class)->add_element (GST_BIN_CAST (src), + src->manager->requester); +#endif + + src->manager->jitterbuffer = gst_element_factory_make ("rtpjitterbuffer", "wfdrtspsrc_jitterbuffer"); + if (G_UNLIKELY (src->manager->jitterbuffer == NULL)) { + GST_ERROR_OBJECT (src, "could not create gstrtpjitterbuffer element"); + return; + } + + GST_BIN_CLASS (parent_class)->add_element (GST_BIN_CAST (src), + src->manager->jitterbuffer); + + src->manager->channelpad[0] = gst_element_get_request_pad (src->manager->session, "recv_rtp_sink"); + if (G_UNLIKELY (src->manager->channelpad[0] == NULL)) { + GST_ERROR_OBJECT (src, "could not create rtp channel pad"); + return; + } + + src->manager->channelpad[1] = gst_element_get_request_pad (src->manager->session, "recv_rtcp_sink"); + if (G_UNLIKELY (src->manager->channelpad[1] == NULL)) { + GST_ERROR_OBJECT (src, "could not create rtcp channel pad"); + return; + } + + //if (!gst_element_link_many(src->manager->session, src->manager->requester, src->manager->jitterbuffer, NULL)) { + if (!gst_element_link_many(src->manager->session, src->manager->jitterbuffer, NULL)) { + GST_ERROR_OBJECT (src, "failed to link elements for wfdrtspsrc"); + return; + } + + /* create ghost pad for using src pad */ + outpad = gst_element_get_static_pad (src->manager->jitterbuffer, "src"); + template = gst_static_pad_template_get (&gst_wfdrtspsrc_src_template); + src->manager->srcpad = gst_ghost_pad_new_from_template ("src", outpad, template); + gst_object_unref (template); + + gst_pad_set_event_function (src->manager->srcpad, + GST_DEBUG_FUNCPTR (gst_wfdrtspsrc_handle_src_event)); + gst_pad_set_query_function (src->manager->srcpad, + GST_DEBUG_FUNCPTR (gst_wfdrtspsrc_handle_src_query)); + + gst_element_add_pad (GST_ELEMENT_CAST (src), src->manager->srcpad); + + src->state = GST_RTSP_STATE_INVALID; + + GST_OBJECT_FLAG_SET (src, GST_ELEMENT_FLAG_SOURCE); +} + +static void +gst_wfdrtspsrc_dispose (GObject * object) +{ + GstWFDRTSPSrc *src = GST_WFDRTSPSRC (object); + WFDRTSPManager *manager = src->manager; + + GST_INFO ("dispose"); + + if (manager->session != NULL) { + GST_BIN_CLASS (parent_class)->remove_element (GST_BIN_CAST (src), + manager->session); + manager->session = NULL; + } + +#if 0 + if (manager->requester != NULL) { + GST_BIN_CLASS (parent_class)->remove_element (GST_BIN_CAST (src), + manager->requester); + manager->requester = NULL; + } +#endif + if (manager->jitterbuffer != NULL) { + GST_BIN_CLASS (parent_class)->remove_element (GST_BIN_CAST (src), + manager->jitterbuffer); + manager->jitterbuffer = NULL; + } + + if (manager->srcpad) { + gst_pad_set_active (manager->srcpad, FALSE); + gst_element_remove_pad (GST_ELEMENT_CAST (src), manager->srcpad); + manager->srcpad = NULL; + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + + +static void +gst_wfdrtspsrc_finalize (GObject * object) +{ + GstWFDRTSPSrc *src; + + src = GST_WFDRTSPSRC (object); + + GST_INFO ("finalize"); + gst_wfd_rtsp_ext_list_free (src->extensions); + gst_rtsp_url_free (src->conninfo.url); + if (src->conninfo.location) + g_free (src->conninfo.location); + src->conninfo.location = NULL; + if (src->conninfo.url_str) + g_free (src->conninfo.url_str); + src->conninfo.url_str = NULL; + if (src->user_id) + g_free (src->user_id); + src->user_id = NULL; + if (src->user_pw) + g_free (src->user_pw); + src->user_pw = NULL; + if (src->user_agent) + g_free (src->user_agent); + src->user_agent = NULL; + if(src->audio_param) { + gst_structure_free(src->audio_param); + src->audio_param = NULL; + } + if(src->video_param) { + gst_structure_free(src->video_param); + src->video_param = NULL; + } + if(src->hdcp_param) { + gst_structure_free(src->hdcp_param); + src->hdcp_param = NULL; + } + + /* free locks */ + g_rec_mutex_clear (src->task_rec_lock); + g_free (src->task_rec_lock); + + g_object_unref (G_OBJECT(src->manager)); +#ifdef G_OS_WIN32 + WSACleanup (); +#endif + + G_OBJECT_CLASS (parent_class)->finalize (object); + GST_INFO ("finalize"); +} + + +/* a proxy string of the format [user:passwd@]host[:port] */ +static gboolean +gst_wfdrtspsrc_set_proxy (GstWFDRTSPSrc * rtsp, const gchar * proxy) +{ + gchar *at = NULL, *col=NULL; + const char * p = NULL; + + 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 = 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; + } + 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_wfdrtspsrc_set_tcp_timeout (GstWFDRTSPSrc * src, guint64 timeout) +{ + src->tcp_timeout.tv_sec = timeout / G_USEC_PER_SEC; + src->tcp_timeout.tv_usec = timeout % G_USEC_PER_SEC; + + if (timeout != 0) + src->ptcp_timeout = &src->tcp_timeout; + else + src->ptcp_timeout = NULL; +} + +static void +gst_wfdrtspsrc_set_property (GObject * object, guint prop_id, const GValue * value, + GParamSpec * pspec) +{ + GstWFDRTSPSrc *src = GST_WFDRTSPSRC (object); + GError *err = NULL; + + switch (prop_id) { + case PROP_LOCATION: + gst_wfdrtspsrc_uri_set_uri (GST_URI_HANDLER (src), + g_value_get_string (value), &err); + break; + case PROP_DEBUG: + src->debug = g_value_get_boolean (value); + break; + case PROP_RETRY: + src->retry = g_value_get_uint (value); + break; + case PROP_TCP_TIMEOUT: + gst_wfdrtspsrc_set_tcp_timeout (src, g_value_get_uint64 (value)); + break; + case PROP_NAT_METHOD: + src->nat_method = g_value_get_enum (value); + break; + case PROP_PROXY: + gst_wfdrtspsrc_set_proxy (src, g_value_get_string (value)); + break; + case PROP_RTP_BLOCKSIZE: + src->rtp_blocksize = g_value_get_uint (value); + break; + case PROP_USER_ID: + if (src->user_id) + g_free (src->user_id); + src->user_id = g_value_dup_string (value); + break; + case PROP_USER_PW: + if (src->user_pw) + g_free (src->user_pw); + src->user_pw = g_value_dup_string (value); + break; + case PROP_USER_AGENT: + if (src->user_agent) + g_free(src->user_agent); + src->user_agent = g_value_dup_string (value); + break; + case PROP_AUDIO_PARAM: + { + const GstStructure *s = gst_value_get_structure (value); + if (src->audio_param) { + gst_structure_free (src->audio_param); + } + if (s) + src->audio_param = gst_structure_copy (s); + else + src->audio_param = NULL; + break; + } + case PROP_VIDEO_PARAM: + { + const GstStructure *s = gst_value_get_structure (value); + if (src->video_param) { + gst_structure_free (src->video_param); + } + if (s) + src->video_param = gst_structure_copy (s); + else + src->video_param = NULL; + break; + } + case PROP_HDCP_PARAM: + { + const GstStructure *s = gst_value_get_structure (value); + if (src->hdcp_param) { + gst_structure_free (src->hdcp_param); + src->hdcp_param = NULL; + } + if (s) + src->hdcp_param = gst_structure_copy (s); + else + src->hdcp_param = NULL; + break; + } + case PROP_DO_RTCP: + g_object_set_property (G_OBJECT (src->manager), "do-rtcp", value); + break; + case PROP_LATENCY: + g_object_set_property (G_OBJECT (src->manager), "latency", value); + break; + case PROP_UDP_BUFFER_SIZE: + g_object_set_property (G_OBJECT (src->manager), "udp-buffer-size", value); + break; + case PROP_UDP_TIMEOUT: + g_object_set_property (G_OBJECT (src->manager), "timeout", value); + break; + case PROP_ENABLE_PAD_PROBE: + { + g_object_set_property (G_OBJECT (src->manager), "enable-pad-probe", value); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_wfdrtspsrc_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstWFDRTSPSrc *src = GST_WFDRTSPSRC (object); + + switch (prop_id) { + case PROP_LOCATION: + g_value_set_string (value, src->conninfo.location); + break; + case PROP_DEBUG: + g_value_set_boolean (value, src->debug); + break; + case PROP_RETRY: + g_value_set_uint (value, src->retry); + break; + case PROP_TCP_TIMEOUT: + { + guint64 timeout; + + timeout = src->tcp_timeout.tv_sec * (guint64)G_USEC_PER_SEC + + src->tcp_timeout.tv_usec; + g_value_set_uint64 (value, timeout); + break; + } + case PROP_NAT_METHOD: + g_value_set_enum (value, src->nat_method); + break; + case PROP_PROXY: + { + gchar *str; + + if (src->proxy_host) { + str = + g_strdup_printf ("%s:%d", src->proxy_host, src->proxy_port); + } else { + str = NULL; + } + g_value_take_string (value, str); + break; + } + case PROP_RTP_BLOCKSIZE: + g_value_set_uint (value, src->rtp_blocksize); + 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_USER_AGENT: + g_value_set_string (value, src->user_agent); + break; + case PROP_AUDIO_PARAM: + gst_value_set_structure (value, src->audio_param); + break; + case PROP_VIDEO_PARAM: + gst_value_set_structure (value, src->video_param); + break; + case PROP_HDCP_PARAM: + gst_value_set_structure (value, src->hdcp_param); + break; + case PROP_DO_RTCP: + g_object_get_property (G_OBJECT (src->manager), "do-rtcp", value); + break; + case PROP_LATENCY: + g_object_get_property (G_OBJECT (src->manager), "latency", value); + break; + case PROP_UDP_BUFFER_SIZE: + g_object_get_property (G_OBJECT (src->manager), "udp-buffer-size", value); + break; + case PROP_UDP_TIMEOUT: + g_object_get_property (G_OBJECT (src->manager), "timeout", value); + break; + case PROP_ENABLE_PAD_PROBE: + g_object_get_property (G_OBJECT (src->manager), "enable-pad-probe", value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_wfdrtspsrc_cleanup (GstWFDRTSPSrc * src) +{ + GST_DEBUG_OBJECT (src, "cleanup"); +} + + +static GstRTSPResult +gst_wfdrtspsrc_connection_send (GstWFDRTSPSrc * src, GstRTSPConnection * conn, + GstRTSPMessage * message, GTimeVal * timeout) +{ + GstRTSPResult ret; + + if (conn) + ret = gst_rtsp_connection_send (conn, message, timeout); + else + ret = GST_RTSP_ERROR; + + return ret; +} + +static GstRTSPResult +gst_wfdrtspsrc_connection_receive (GstWFDRTSPSrc * src, GstRTSPConnection * conn, + GstRTSPMessage * message, GTimeVal * timeout) +{ + GstRTSPResult ret; + + if (conn) + ret = gst_rtsp_connection_receive (conn, message, timeout); + else + ret = GST_RTSP_ERROR; + + return ret; +} + +static gboolean +gst_wfdrtspsrc_prepare_set_param (GstWFDRTSPSrc * src, GstWFDParam param) +{ + GstRTSPMessage request = { 0 }; + GstRTSPMessage response = { 0 }; + GstRTSPResult res = GST_RTSP_OK; + WFDResult wfd_res = WFD_OK; + WFDMessage *msg_no= NULL; + gchar *msg; + gchar *ua; + guint msglen = 0; + GString *msglength; + + res = gst_rtsp_message_init_request (&request, GST_RTSP_SET_PARAMETER, + src->conninfo.url_str); + if (res < 0) + goto error; + + /* Create set_parameter body to be sent in the request */ + + wfd_res = wfdconfig_message_new (&msg_no); + if (wfd_res != WFD_OK) { + GST_ERROR_OBJECT (src, "Failed to create wfd message..."); + res = GST_RTSP_ERROR; + goto error; + } + + wfd_res = wfdconfig_message_init(msg_no); + if (wfd_res != WFD_OK) { + GST_ERROR_OBJECT (src, "Failed to init wfd message..."); + res = GST_RTSP_ERROR; + goto error; + } + + switch(param) { + + case WFD_ROUTE: { + wfd_res = wfdconfig_set_audio_sink_type(msg_no,WFD_SECONDARY_SINK); + if (wfd_res != WFD_OK) { + GST_ERROR_OBJECT (src, "Failed to set audio sink type..."); + res = GST_RTSP_ERROR; + goto error; + } + break; + } + + case WFD_CONNECTOR_TYPE: { + wfd_res = wfdconfig_set_connector_type(msg_no,WFD_CONNECTOR_VGA); + if (wfd_res != WFD_OK) { + GST_ERROR_OBJECT (src, "Failed to set connector type..."); + res = GST_RTSP_ERROR; + goto error; + } + break; + } + + case WFD_STANDBY: { + wfd_res = wfdconfig_set_standby(msg_no,TRUE); + if (wfd_res != WFD_OK) { + GST_ERROR_OBJECT (src, "Failed to set standby..."); + res = GST_RTSP_ERROR; + goto error; + } + break; + } + + case WFD_IDR_REQUEST: { + wfd_res = wfdconfig_set_idr_request(msg_no); + if (wfd_res != WFD_OK) { + GST_ERROR_OBJECT (src, "Failed to set IDR request..."); + res = GST_RTSP_ERROR; + goto error; + } + break; + } + + case WFD_UIBC_CAPABILITY: { + wfd_res = wfdconfig_set_uibc_capability(msg_no, WFD_UIBC_INPUT_CAT_UNKNOWN, 0, NULL, 0, 0); + if (wfd_res != WFD_OK) { + GST_ERROR_OBJECT (src, "Failed to set UIBC capability..."); + res = GST_RTSP_ERROR; + goto error; + } + break; + } + + case WFD_UIBC_SETTING: { + wfd_res = wfdconfig_set_uibc_status(msg_no, TRUE); + if (wfd_res != WFD_OK) { + GST_ERROR_OBJECT (src, "Failed to set UIBC setting..."); + res = GST_RTSP_ERROR; + goto error; + } + break; + } + + default: { + GST_ERROR_OBJECT (src, "Unhandled WFD message type..."); + if(msg_no) + wfdconfig_message_free(msg_no); + msg_no = NULL; + gst_rtsp_message_unset (&request); + gst_rtsp_message_unset (&response); + return GST_RTSP_EINVAL; + } + } + + wfd_res = wfdconfig_message_dump(msg_no); + if (wfd_res != WFD_OK) { + GST_ERROR_OBJECT (src, "Failed to dump wfd message..."); + res = GST_RTSP_ERROR; + goto error; + } + + msg = wfdconfig_message_as_text(msg_no); + if (msg == NULL) { + GST_ERROR_OBJECT (src, "Failed to get wfd message as text..."); + res = GST_RTSP_ERROR; + goto error; + } + + msglen = strlen(msg); + msglength = g_string_new (""); + g_string_append_printf (msglength,"%d",msglen); + + ua = g_strdup (src->user_agent); + res = gst_rtsp_message_add_header (&request, GST_RTSP_HDR_USER_AGENT, ua); + if (ua) + g_free(ua); + + GST_DEBUG ("WFD message body: %s", msg); + /* add content-length type */ + res = gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CONTENT_LENGTH, g_string_free (msglength, FALSE)); + if (res != GST_RTSP_OK) { + GST_ERROR_OBJECT (src, "Failed to add header to rtsp request..."); + goto error; + } + + /* adding wfdconfig data to request */ + res = gst_rtsp_message_set_body (&request,(guint8 *)msg, msglen); + if (res != GST_RTSP_OK) { + GST_ERROR_OBJECT (src, "Failed to set body to rtsp request..."); + goto error; + } + + wfdconfig_message_free(msg_no); + msg_no = NULL; + + /* send SET_PARAM */ + GST_DEBUG_OBJECT (src, "send SET_PARAM..."); + + if (gst_wfdrtspsrc_send (src, src->conninfo.connection, &request, &response, + NULL) < 0) + goto error; + + if (src->debug) + wfd_rtsp_manager_message_dump (&response); + + return TRUE; + +/* ERRORS */ +error: + { + if(msg_no) + wfdconfig_message_free(msg_no); + gst_rtsp_message_unset (&request); + gst_rtsp_message_unset (&response); + return FALSE; + } +} + +static gboolean +gst_wfdrtspsrc_handle_src_event (GstPad * pad, GstObject *parent, GstEvent * event) +{ + GstWFDRTSPSrc *src; + gboolean res = TRUE; + gboolean forward = FALSE; + const GstStructure *s; + /*static gdouble elapsed = 0.0; + static int count = 0;*/ + + src = GST_WFDRTSPSRC_CAST (gst_pad_get_parent (pad)); + if(src == NULL) { + GST_ERROR_OBJECT (src, "src is NULL."); + return FALSE; + } + + //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_QOS: + case GST_EVENT_NAVIGATION: + case GST_EVENT_LATENCY: + break; + case GST_EVENT_CUSTOM_UPSTREAM: + s = gst_event_get_structure (event); + if (gst_structure_has_name (s, "WFD_FORCE_IDR")) { + /* Send IDR request */ + res = gst_wfdrtspsrc_prepare_set_param(src, WFD_IDR_REQUEST); + } + break; + 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); + } + gst_object_unref (src); + + return res; +} + +/* this query is executed on the ghost source pad exposed on manager. */ +static gboolean +gst_wfdrtspsrc_handle_src_query (GstPad * pad, GstObject *parent, GstQuery * query) +{ + GstWFDRTSPSrc *src = NULL; + gboolean res = FALSE; + + src = GST_WFDRTSPSRC_CAST (gst_pad_get_parent (pad)); + if(src == NULL) + { + GST_ERROR_OBJECT (src, "src is NULL."); + return res; + } + + //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_URI: + { + if (src->conninfo.location == NULL) { + res = FALSE; + } else { + gst_query_set_uri( query, src->conninfo.location); + 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; + } + } + gst_object_unref (src); + + return res; +} + + +/* 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_wfdrtspsrc_send_dummy_packets (GstWFDRTSPSrc * src) +{ + WFDRTSPManager *manager = src->manager; + + if (src->nat_method != GST_WFD_RTSP_NAT_DUMMY) + return TRUE; + + if (manager) { + if (manager->fakesrc && manager->udpsink[0]) { + GST_DEBUG_OBJECT (src, "sending dummy packet to manager %p", manager); + gst_element_set_state (manager->udpsink[0], GST_STATE_NULL); + gst_element_set_state (manager->fakesrc, GST_STATE_NULL); + gst_element_set_state (manager->udpsink[0], GST_STATE_PLAYING); + gst_element_set_state (manager->fakesrc, GST_STATE_PLAYING); + } + } + + return TRUE; +} + + +static void +gst_wfdrtspsrc_configure_caps (GstWFDRTSPSrc * src) +{ + WFDRTSPManager *manager = src->manager;; + GstCaps *caps; + guint64 start, stop; + gdouble play_speed, play_scale; + GstStructure *structure; + + GST_DEBUG_OBJECT (src, "configuring manager caps"); + + start = 0; + stop = GST_CLOCK_TIME_NONE; + play_speed = 1.000; + play_scale = 1.000; + + if ((caps = manager->caps)) { + caps = gst_caps_make_writable (caps); + structure = gst_caps_get_structure (caps, 0); + /* update caps */ + if (manager->timebase != GST_CLOCK_TIME_NONE) + gst_structure_set (structure, "clock-base", G_TYPE_UINT, + (guint) manager->timebase, NULL); + if (manager->seqbase != GST_CLOCK_TIME_NONE) + gst_structure_set (structure, "seqnum-base", G_TYPE_UINT, + (guint) manager->seqbase, NULL); + gst_structure_set (structure, "npt-start", G_TYPE_UINT64, start, NULL); + + if (stop != GST_CLOCK_TIME_NONE) + gst_structure_set (structure, "npt-stop", G_TYPE_UINT64, stop, NULL); + gst_structure_set (structure, "play-speed", G_TYPE_DOUBLE, play_speed, NULL); + gst_structure_set (structure, "play-scale", G_TYPE_DOUBLE, play_scale, NULL); + gst_structure_set (structure, "height", G_TYPE_INT, src->video_height, NULL); + gst_structure_set (structure, "width", G_TYPE_INT, src->video_width, NULL); + gst_structure_set (structure, "video-framerate", G_TYPE_INT, src->video_framerate, NULL); + + GST_DEBUG_OBJECT(src, "Frame rate : %d", src->video_framerate); + + manager->caps = caps; + +#ifdef _SET_FRAMERATE_TO_CAPS + /* Set caps to udpsrc */ + GstCaps *udp_caps = NULL; + GstStructure *s = NULL; + g_object_get(manager->udpsrc[0], "caps", &udp_caps, NULL); + udp_caps = gst_caps_make_writable (udp_caps); + s = gst_caps_get_structure (udp_caps, 0); + gst_structure_set (s, "npt-start", G_TYPE_UINT64, start, NULL); + gst_structure_set (s, "npt-stop", G_TYPE_UINT64, stop, NULL); + gst_structure_set (s, "play-speed", G_TYPE_DOUBLE, play_speed, NULL); + gst_structure_set (s, "play-scale", G_TYPE_DOUBLE, play_scale, NULL); + gst_structure_set (s, "width", G_TYPE_INT, src->video_width, NULL); + gst_structure_set (s, "height", G_TYPE_INT, src->video_height, NULL); + gst_structure_set (s, "video-framerate", G_TYPE_INT, src->video_framerate, NULL); + g_object_set(manager->udpsrc[0], "caps", udp_caps, NULL); +#endif + } + GST_DEBUG_OBJECT (src, "manager %p, caps %" GST_PTR_FORMAT, manager, caps); + + if (manager->srcpad) { + GST_DEBUG_OBJECT (src, "set caps for srcpad"); + gst_pad_set_caps(manager->srcpad, manager->caps); + } +} + +static gboolean +gst_wfdrtspsrc_stream_push_event (WFDRTSPManager * manager, GstEvent * event, gboolean source) +{ + gboolean res = TRUE; + + if (manager->srcpad == NULL) + goto done; + + if (source && manager->udpsrc[0]) { + gst_event_ref (event); + res = gst_element_send_event (manager->udpsrc[0], event); + } else if (manager->channelpad[0]) { + gst_event_ref (event); + if (GST_PAD_IS_SRC (manager->channelpad[0])) + res = gst_pad_push_event (manager->channelpad[0], event); + else + res = gst_pad_send_event (manager->channelpad[0], event); + } + + if (source && manager->udpsrc[1]) { + gst_event_ref (event); + res &= gst_element_send_event (manager->udpsrc[1], event); + } else if (manager->channelpad[1]) { + gst_event_ref (event); + if (GST_PAD_IS_SRC (manager->channelpad[1])) + res &= gst_pad_push_event (manager->channelpad[1], event); + else + res &= gst_pad_send_event (manager->channelpad[1], event); + } + +#if 0 + if (source && manager->udpsrc[2]) { + gst_event_ref (event); + res &= gst_element_send_event (manager->udpsrc[2], event); + } else if (manager->channelpad[2]) { + gst_event_ref (event); + if (GST_PAD_IS_SRC (manager->channelpad[2])) + res &= gst_pad_push_event (manager->channelpad[2], event); + else + res &= gst_pad_send_event (manager->channelpad[2], event); + } +#endif + +done: + gst_event_unref (event); + + return res; +} + +static gboolean +gst_wfdrtspsrc_push_event (GstWFDRTSPSrc * src, GstEvent * event, gboolean source) +{ + gboolean res = TRUE; + + if (src->manager) { + gst_event_ref (event); + res = gst_wfdrtspsrc_stream_push_event (src->manager, event, source); + gst_event_unref (event); + } + + return res; +} + +static GstRTSPResult +gst_wfdrtspsrc_conninfo_connect (GstWFDRTSPSrc * src, GstWFDRTSPConnInfo * info) +{ + GstRTSPResult res; + + 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 (info->url_str) + 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_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 */ + GST_DEBUG_OBJECT (src, "connecting (%s)...", info->location); + int retry = 0; +connect_retry: + if (src->do_stop) { + GST_ERROR_OBJECT (src, "stop connecting...."); + return GST_RTSP_EINTR; + } + + if ((res = + gst_rtsp_connection_connect (info->connection, + src->ptcp_timeout)) < 0) { + if (retry < 50) { + GST_ERROR_OBJECT(src, "Connection failed... Try again..."); + usleep(100000); + retry++; + goto connect_retry; + } else { + goto could_not_connect; + } + } else { + GST_INFO_OBJECT(src, "Connection success"); + } + + info->connected = TRUE; + } + return GST_RTSP_OK; + + /* ERRORS */ +parse_error: + { + GST_ERROR_OBJECT (src, "No valid RTSP URL was provided"); + return res; + } +could_not_create: + { + gchar *str = gst_rtsp_strresult (res); + GST_ERROR_OBJECT (src, "Could not create connection. (%s)", str); + g_free (str); + 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); + return res; + } +} + +static GstRTSPResult +gst_wfdrtspsrc_conninfo_close (GstWFDRTSPSrc * src, GstWFDRTSPConnInfo * info, + gboolean free) +{ + g_return_val_if_fail (info, GST_RTSP_EINVAL); + + 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; + } + return GST_RTSP_OK; +} + +static GstRTSPResult +gst_wfdrtspsrc_conninfo_reconnect (GstWFDRTSPSrc * src, GstWFDRTSPConnInfo * info) +{ + GstRTSPResult res; + + GST_DEBUG_OBJECT (src, "reconnecting connection..."); + gst_wfdrtspsrc_conninfo_close (src, info, FALSE); + res = gst_wfdrtspsrc_conninfo_connect (src, info); + + return res; +} + +static void +gst_wfdrtspsrc_connection_flush (GstWFDRTSPSrc * src, gboolean flush) +{ + GST_DEBUG_OBJECT (src, "set flushing %d", flush); + if (src->conninfo.connection) { + GST_DEBUG_OBJECT (src, "connection flush %d", flush); + gst_rtsp_connection_flush (src->conninfo.connection, flush); + } + + if (src->manager) { + WFDRTSPManager *manager = src->manager; + GST_DEBUG_OBJECT (src, "manager %p flush %d", manager, flush); + if (manager->conninfo.connection) + gst_rtsp_connection_flush (manager->conninfo.connection, flush); + } + GST_DEBUG_OBJECT (src, "flushing %d is done", flush); +} + + +static GstRTSPResult +gst_wfdrtspsrc_handle_request (GstWFDRTSPSrc * src, GstRTSPConnection * conn, + GstRTSPMessage * request) +{ + GstRTSPMessage response = { 0 }; + GstRTSPResult res; + GstRTSPMethod method; + const gchar *uristr; + GstRTSPVersion version; + GstRTSPMethod options; + gchar *str; + gchar *ua; + guint8 *data; + guint size; + + GST_DEBUG_OBJECT (src, "got server request message"); + + res = gst_wfd_rtsp_ext_list_receive_request (src->extensions, request); + + gst_rtsp_message_parse_request (request, &method, &uristr, &version); + + if (version != GST_RTSP_VERSION_1_0) { + /* we can only handle 1.0 requests */ + res = GST_RTSP_ENOTIMPL; + } + + if (src->debug) + wfd_rtsp_manager_message_dump (request); + + switch(method) { + case GST_RTSP_OPTIONS: + { + gchar *tmp = NULL; + char *options_str = NULL; + + options = GST_RTSP_GET_PARAMETER |GST_RTSP_SET_PARAMETER; + + str = gst_rtsp_options_as_text (options); + + tmp = g_strdup (", org.wfa.wfd1.0"); + + GST_LOG ("tmp = %s\n\n", tmp); + + options_str = (char *) malloc (strlen(tmp) + strlen (str) + 1); + if (!options_str) { + GST_ERROR ("Failed to allocate memory..."); + res = GST_RTSP_ENOMEM; + goto send_error; + } else { + strncpy (options_str, str, strlen (str)); + strncpy (options_str+strlen(str), tmp, strlen (tmp)); + options_str [strlen(tmp) + strlen (str)] = '\0'; + + GST_LOG ("\n\noptions_str = %s\n\n", options_str); + } + GST_DEBUG_OBJECT (src, "Creating OPTIONS response"); + + res = gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, + gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); + if(res < 0) { + if(options_str) + g_free (options_str); + goto send_error; + } + ua = g_strdup(src->user_agent); + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_PUBLIC, options_str); + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_USER_AGENT, ua); + if(options_str) + g_free (options_str); + if(ua) + g_free (ua); + break; + } + + case GST_RTSP_GET_PARAMETER: + { + gchar *msg; + guint msglen = 0; + GString *msglength; + WFDMessage *msg3rep; + WFDResult wfd_res = WFD_OK; + + GST_DEBUG_OBJECT (src, "Got GET_PARAMETER request"); + + res = gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); + if(res < 0) + goto send_error; + + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_TYPE, "text/parameters"); + + ua = g_strdup(src->user_agent); + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_USER_AGENT, ua); + + gst_rtsp_message_get_body (request, &data, &size); + + /* Check if message is keep-alive if body is empty*/ + if(size==0) { + res = gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, "OK", + request); + gst_rtsp_connection_reset_timeout (src->conninfo.connection); + if (res < 0) + goto send_error; + break; + } + + /* Creating WFD parameters supported to send as response for + * GET_PARAMETER request from server*/ + + wfdconfig_message_new(&msg3rep); + if(msg3rep == NULL) { + res = GST_RTSP_ERROR; + goto send_error; + } + + wfd_res = wfdconfig_message_init(msg3rep); + + wfd_res = wfdconfig_message_parse_buffer(data,size,msg3rep); + + if(wfd_res != WFD_OK) { + res = GST_RTSP_ERROR; + goto send_error; + } + wfdconfig_message_dump(msg3rep); + + /* Check if the request message has "wfd_audio_codecs" in it */ + if(msg3rep->audio_codecs) { + guint audio_codec = 0; + guint audio_sampling_frequency = 0; + guint audio_channels = 0; + guint audio_latency = 0; + //reading audio parameters which are set from sink ini file + if(src->audio_param != NULL) { + if (gst_structure_has_field (src->audio_param, "audio_codec")) { + gst_structure_get_uint (src->audio_param, "audio_codec", &audio_codec); + } + if (gst_structure_has_field (src->audio_param, "audio_latency")) { + gst_structure_get_uint (src->audio_param, "audio_latency", &audio_latency); + } + if (gst_structure_has_field (src->audio_param, "audio_channels")) { + gst_structure_get_uint (src->audio_param, "audio_channels", &audio_channels); + } + if (gst_structure_has_field (src->audio_param, "audio_sampling_frequency")) { + gst_structure_get_uint (src->audio_param, "audio_sampling_frequency", &audio_sampling_frequency); + } + } + + wfd_res = wfdconfig_set_supported_audio_format(msg3rep, audio_codec, + audio_sampling_frequency, audio_channels, 16, audio_latency); + } + + /* Check if the request message has "wfd_video_formats" in it */ + if(msg3rep->video_formats) { + guint video_codec = 0; + guint video_native_resolution = 0; + guint video_cea_support = 0; + guint video_vesa_support = 0; + guint video_hh_support = 0; + guint video_profile = 0; + guint video_level = 0; + guint video_latency = 0; + gint video_vertical_resolution = 0; + gint video_horizontal_resolution = 0; + gint video_minimum_slicing = 0; + gint video_slice_enc_param = 0; + gint video_framerate_control_support = 0; + + //reading video parameters which are set from sink ini file + if (src->video_param != NULL) { + if (gst_structure_has_field (src->video_param, "video_codec")) { + gst_structure_get_uint (src->video_param, "video_codec", &video_codec); + } + if (gst_structure_has_field (src->video_param, "video_native_resolution")) { + gst_structure_get_uint (src->video_param, "video_native_resolution", &video_native_resolution); + } + if (gst_structure_has_field (src->video_param, "video_cea_support")) { + gst_structure_get_uint (src->video_param, "video_cea_support", &video_cea_support); + } + if (gst_structure_has_field (src->video_param, "video_vesa_support")) { + gst_structure_get_uint (src->video_param, "video_vesa_support", &video_vesa_support); + } + if (gst_structure_has_field (src->video_param, "video_hh_support")) { + gst_structure_get_uint (src->video_param, "video_hh_support", &video_hh_support); + } + if (gst_structure_has_field (src->video_param, "video_profile")) { + gst_structure_get_uint (src->video_param, "video_profile", &video_profile); + } + if (gst_structure_has_field (src->video_param, "video_level")) { + gst_structure_get_uint (src->video_param, "video_level", &video_level); + } + if (gst_structure_has_field (src->video_param, "video_latency")) { + gst_structure_get_uint (src->video_param, "video_latency", &video_latency); + } + if (gst_structure_has_field (src->video_param, "video_vertical_resolution")) { + gst_structure_get_int (src->video_param, "video_vertical_resolution", &video_vertical_resolution); + } + if (gst_structure_has_field (src->video_param, "video_horizontal_resolution")) { + gst_structure_get_int (src->video_param, "video_horizontal_resolution", &video_horizontal_resolution); + } + if (gst_structure_has_field (src->video_param, "video_minimum_slicing")) { + gst_structure_get_int (src->video_param, "video_minimum_slicing", &video_minimum_slicing); + } + if (gst_structure_has_field (src->video_param, "video_slice_enc_param")) { + gst_structure_get_int (src->video_param, "video_slice_enc_param", &video_slice_enc_param); + } + if (gst_structure_has_field (src->video_param, "video_framerate_control_support")) { + gst_structure_get_int (src->video_param, "video_framerate_control_support", &video_framerate_control_support); + } + } + + + wfd_res = wfdconfig_set_supported_video_format(msg3rep, video_codec, + WFD_VIDEO_CEA_RESOLUTION, video_native_resolution, + video_cea_support, + video_vesa_support, + video_hh_support, + video_profile, video_level, video_latency, video_vertical_resolution, video_horizontal_resolution, video_minimum_slicing, video_slice_enc_param, video_framerate_control_support); + } + + /* Check if the request has "wfd_client_rtp_ports" in it */ + if(msg3rep->client_rtp_ports) { + /* Hardcoded as of now. This is to comply with dongle port settings. + This should be derived from gst_wfdrtspsrc_alloc_udp_ports */ + src->primary_rtpport = 19000; + src->secondary_rtpport = 0; + wfd_res = wfdconfig_set_prefered_RTP_ports(msg3rep, WFD_RTSP_TRANS_RTP, WFD_RTSP_PROFILE_AVP, + WFD_RTSP_LOWER_TRANS_UDP, src->primary_rtpport, src->secondary_rtpport); + } + + if(wfd_res != WFD_OK) { + res = GST_RTSP_ERROR; + goto send_error; + } + + /* Check if the request has "wfd_3d_video_formats " in it */ + if(msg3rep->video_3d_formats) { + /* TODO: Set preferred 3d_video_formats */ + wfd_res = WFD_OK; + } + + /* When set preferred 3d_video_formats is done, following block need to be uncommented */ + /*if(wfd_res != WFD_OK) { + res = GST_RTSP_ERROR; + goto send_error; + }*/ + + /* Check if the request has "wfd_content_protection " in it */ + if(msg3rep->content_protection) { + gint hdcp_version = 0; + gint hdcp_port_no = 0; + //reading hdcp parameters which are set from sink ini file + if (src->hdcp_param != NULL) { + if (gst_structure_has_field (src->hdcp_param, "hdcp_version")) { + gst_structure_get_int (src->hdcp_param, "hdcp_version", &hdcp_version); + GST_DEBUG_OBJECT(src, "hdcp version : %d", hdcp_version); + } + + if (gst_structure_has_field (src->hdcp_param, "hdcp_port_no")) { + gst_structure_get_int (src->hdcp_param, "hdcp_port_no", &hdcp_port_no); + GST_DEBUG_OBJECT(src, "hdcp_port_no : %d", hdcp_port_no); + } + } else { + GST_DEBUG_OBJECT(src, "No HDCP"); + } + + wfd_res = wfdconfig_set_contentprotection_type(msg3rep, hdcp_version, (guint32)hdcp_port_no); + } + + if(wfd_res != WFD_OK) { + res = GST_RTSP_ERROR; + goto send_error; + } + /* Check if the request has "wfd_display_edid" in it */ + if(msg3rep->display_edid) { + /* TODO: Set preferred display_edid */ + wfd_res = WFD_OK; + } + + /* when set preferred display_edid following block need to be uncommented. */ + /*if(wfd_res != WFD_OK) { + res = GST_RTSP_ERROR; + goto send_error; + }*/ + + /* Check if the request has "wfd_coupled_sink" in it */ + if(msg3rep->coupled_sink) { + //wfd_res = wfdconfig_set_coupled_sink(msg3rep, WFD_SINK_NOT_COUPLED, NULL); + /* To test with dummy coupled sink address */ + wfd_res = wfdconfig_set_coupled_sink(msg3rep,WFD_SINK_COUPLED,(gchar *)"1.0.0.1:435"); + } + + if(wfd_res != WFD_OK) { + res = GST_RTSP_ERROR; + goto send_error; + } + msg = wfdconfig_message_as_text(msg3rep); + + msglen = strlen(msg); + msglength = g_string_new (""); + g_string_append_printf (msglength,"%d",msglen); + + GST_DEBUG_OBJECT (src, "GET_PARAMETER response message body: %s\n\n", msg); + + gst_rtsp_message_set_body (&response, (guint8*) msg, msglen); + + wfdconfig_message_free(msg3rep); + + if(ua) + g_free(ua); + + break; + } + + case GST_RTSP_SET_PARAMETER: + { + WFDMessage *msg = NULL; + WFDResult wfd_res = WFD_OK; + gchar *url0, *url1; + + GST_DEBUG_OBJECT (src, "Got SET_PARAMETER request"); + + res = gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, + gst_rtsp_status_as_text (GST_RTSP_STS_OK), request); + if (res < 0) + goto send_error; + + ua = g_strdup (src->user_agent); + gst_rtsp_message_add_header (&response, GST_RTSP_HDR_USER_AGENT, ua); + + gst_rtsp_message_get_body (request, &data, &size); + + wfdconfig_message_new(&msg); + if(msg == NULL) { + res = GST_RTSP_ERROR; + goto send_error; + } + + wfd_res = wfdconfig_message_init(msg); + if(wfd_res != WFD_OK) { + res = GST_RTSP_ERROR; + goto send_error; + } + wfd_res = wfdconfig_message_parse_buffer(data,size,msg); + if(wfd_res != WFD_OK) { + res = GST_RTSP_ERROR; + goto send_error; + } + + if (g_strrstr((gchar*)data, "wfd_av_format_change_timing")) { + /* TODO: this is to handle Set parameter request from intel widi src */ + GST_DEBUG_OBJECT(src, "Got Another SET_PARAM "); + break; + } + + if(msg->video_formats || msg->audio_codecs) { + GstStructure *stream_info; + gint num_of_stream = 0; + + wfdconfig_message_dump(msg); + + if(g_strrstr((gchar*)data,"wfd_audio_codecs")) { + wfd_res = gst_wfdrtspsrc_get_audio_parameter(src, msg); + num_of_stream ++; + } + + if(g_strrstr((gchar*)data,"wfd_video_formats")) { + wfd_res = gst_wfdrtspsrc_get_video_parameter(src, msg); + num_of_stream ++; + } + + stream_info = gst_structure_new ("WFDStreamInfo", + "num_of_stream", G_TYPE_INT, num_of_stream, + "audio_format", G_TYPE_STRING, src->audio_format, + "audio_channels", G_TYPE_INT, src->audio_channels, + "audio_rate", G_TYPE_INT, src->audio_frequency, + "audio_bitwidth", G_TYPE_INT, src->audio_bitwidth/16, + "video_format", G_TYPE_STRING, "H264", + "video_width", G_TYPE_INT, src->video_width, + "video_height", G_TYPE_INT, src->video_height, + "video_framerate", G_TYPE_INT, src->video_framerate, + NULL); + g_signal_emit (src, gst_wfdrtspsrc_signals[SIGNAL_UPDATE_MEDIA_INFO], 0, stream_info); + + wfd_res = wfdconfig_get_presentation_url(msg, &url0, &url1); + if(wfd_res == WFD_OK) { + g_free (src->conninfo.location); + src->conninfo.location = g_strdup (url0); + /* url1 is ignored as of now */ + } else { + res = GST_RTSP_ERROR; + goto send_error; + } + } + + if(msg->standby) { + gboolean standby_enable; + wfd_res = wfdconfig_get_standby(msg, &standby_enable); + if(wfd_res == WFD_OK) + GST_DEBUG("M12 server set param request STANDBY %s", standby_enable?"ENABLE":"DISABLE"); + } + + /* DEAD CODE It will be used for UIBC implementation + else if(g_strrstr((gchar*)data,"wfd_standby")) { + gboolean uibc_enable; + wfd_res = wfdconfig_get_uibc_status(msg, &uibc_enable); + if(wfd_res == WFD_OK) + GST_DEBUG("M15 server set param request for UIBC %s", uibc_enable?"ENABLE":"DISABLE"); + }*/ + if (ua) + g_free(ua); + break; + } + + default: + { + res = gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, "OK", + request); + if (res < 0) + goto send_error; + break; + } + } + + if (src->debug) + wfd_rtsp_manager_message_dump (&response); + + res = gst_wfdrtspsrc_connection_send (src, conn, &response, NULL); + if (res < 0) + goto send_error; + + /* Handling wfd_trigger_method: PAUSE */ + if(method == GST_RTSP_SET_PARAMETER && g_strrstr((gchar*)data,"PAUSE")) { + GST_DEBUG_OBJECT (src, "trigger PAUSE \n"); + gst_wfdrtspsrc_loop_send_cmd (src, CMD_PAUSE); + } + + /* Handling wfd_trigger_method: RESUME */ + if(method == GST_RTSP_SET_PARAMETER && g_strrstr((gchar*)data,"PLAY")) { + GST_DEBUG_OBJECT (src, "trigger RESUME \n"); + gst_wfdrtspsrc_loop_send_cmd (src, CMD_PLAY); + } + + /* Handling wfd_trigger_method: TEARDOWN */ + if(method == GST_RTSP_SET_PARAMETER && g_strrstr((gchar*)data,"TEARDOWN")) { + GstBus *bus; + + GST_DEBUG_OBJECT (src, "trigger TEARDOWN \n"); + + gst_wfdrtspsrc_loop_send_cmd (src, CMD_CLOSE); + + bus = gst_element_get_bus(GST_ELEMENT_CAST(src)); + if(!gst_bus_post(bus, gst_message_new_application(GST_OBJECT_CAST(src), gst_structure_new_empty("TEARDOWN")))){ + GST_ERROR_OBJECT(src, "Failed to send TEARDOWN message\n"); + } + gst_object_unref(bus); + + goto exit; + } + + /* Handling wfd_trigger_method: setup */ + if(method == GST_RTSP_SET_PARAMETER && g_strrstr((gchar*)data,"SETUP")) { + src->state = GST_RTSP_STATE_INIT; + + /* setup streams */ + if (!gst_wfdrtspsrc_setup (src)) + goto setup_failed; + + src->state = GST_RTSP_STATE_READY; + } + +exit: + gst_rtsp_message_unset (request); + gst_rtsp_message_unset (&response); + + return GST_RTSP_OK; + +setup_failed: + return GST_RTSP_ERROR; + + /* ERRORS */ +send_error: + { + gst_rtsp_message_unset (request); + gst_rtsp_message_unset (&response); + return res; + } + +} + +/* send server keep-alive */ +static GstRTSPResult +gst_wfdrtspsrc_send_keep_alive (GstWFDRTSPSrc * src) +{ + GstRTSPMessage request = { 0 }; + GstRTSPResult res; + GstRTSPMethod method; + gchar *control; + + GST_INFO_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 = src->conninfo.url_str; + + if (control == NULL) + goto no_control; + + res = gst_rtsp_message_init_request (&request, method, control); + if (res < 0) + goto send_error; + + if (src->debug && request.body != NULL) + wfd_rtsp_manager_message_dump (&request); + + res = + gst_wfdrtspsrc_connection_send (src, src->conninfo.connection, &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 void +gst_wfdrtspsrc_loop_start_cmd (GstWFDRTSPSrc * src, gint cmd) +{ + GST_DEBUG_OBJECT (src, "start cmd %d", cmd); + + switch (cmd) { + case CMD_OPEN: + GST_ELEMENT_PROGRESS (src, START, "open", ("Opening Stream")); + break; + case CMD_PLAY: + GST_ELEMENT_PROGRESS (src, START, "play", ("Sending PLAY request")); + break; + case CMD_PAUSE: + GST_ELEMENT_PROGRESS (src, START, "pause", ("Sending PAUSE request")); + break; + case CMD_CLOSE: + GST_ELEMENT_PROGRESS (src, START, "close", ("Closing Stream")); + break; + default: + break; + } +} + +static void +gst_wfdrtspsrc_loop_complete_cmd (GstWFDRTSPSrc * src, gint cmd) +{ + GST_DEBUG_OBJECT (src, "complete cmd %d", cmd); + + switch (cmd) { + case CMD_OPEN: + GST_ELEMENT_PROGRESS (src, COMPLETE, "open", ("Opened Stream")); + break; + case CMD_PLAY: + GST_ELEMENT_PROGRESS (src, COMPLETE, "play", ("Sent PLAY request")); + break; + case CMD_PAUSE: + GST_ELEMENT_PROGRESS (src, COMPLETE, "pause", ("Sent PAUSE request")); + break; + case CMD_CLOSE: + GST_ELEMENT_PROGRESS (src, COMPLETE, "close", ("Closed Stream")); + break; + default: + break; + } +} + +static void +gst_wfdrtspsrc_loop_cancel_cmd (GstWFDRTSPSrc * src, gint cmd) +{ + GST_DEBUG_OBJECT (src, "cancel cmd %d", cmd); + + switch (cmd) { + case CMD_OPEN: + GST_ELEMENT_PROGRESS (src, CANCELED, "open", ("Open canceled")); + break; + case CMD_PLAY: + GST_ELEMENT_PROGRESS (src, CANCELED, "play", ("PLAY canceled")); + break; + case CMD_PAUSE: + GST_ELEMENT_PROGRESS (src, CANCELED, "pause", ("PAUSE canceled")); + break; + case CMD_CLOSE: + GST_ELEMENT_PROGRESS (src, CANCELED, "close", ("Close canceled")); + break; + default: + break; + } +} + +static void +gst_wfdrtspsrc_loop_error_cmd (GstWFDRTSPSrc * src, gint cmd) +{ + GST_DEBUG_OBJECT (src, "error cmd %d", cmd); + + switch (cmd) { + case CMD_OPEN: + GST_ELEMENT_PROGRESS (src, ERROR, "open", ("Open failed")); + break; + case CMD_PLAY: + GST_ELEMENT_PROGRESS (src, ERROR, "play", ("PLAY failed")); + break; + case CMD_PAUSE: + GST_ELEMENT_PROGRESS (src, ERROR, "pause", ("PAUSE failed")); + break; + case CMD_CLOSE: + GST_ELEMENT_PROGRESS (src, ERROR, "close", ("Close failed")); + break; + default: + break; + } +} + +static void +gst_wfdrtspsrc_loop_end_cmd (GstWFDRTSPSrc * src, gint cmd, GstRTSPResult ret) +{ + GST_DEBUG_OBJECT (src, "end cmd %d", cmd); + + if (ret == GST_RTSP_OK) + gst_wfdrtspsrc_loop_complete_cmd (src, cmd); + else if (ret == GST_RTSP_EINTR) + gst_wfdrtspsrc_loop_cancel_cmd (src, cmd); + else + gst_wfdrtspsrc_loop_error_cmd (src, cmd); +} + +static void +gst_wfdrtspsrc_loop_send_cmd (GstWFDRTSPSrc * src, gint cmd) +{ + gint old; + + /* start new request */ + gst_wfdrtspsrc_loop_start_cmd (src, cmd); + + GST_OBJECT_LOCK (src); + + GST_DEBUG_OBJECT (src, "sending cmd %d", cmd); + + old = src->loop_cmd; + if (old != CMD_WAIT) { + src->loop_cmd = CMD_WAIT; + GST_OBJECT_UNLOCK (src); + /* cancel previous request */ + gst_wfdrtspsrc_loop_cancel_cmd (src, old); + GST_OBJECT_LOCK (src); + } + src->loop_cmd = cmd; + + /* interrupt if allowed */ + if (src->waiting) { + GST_DEBUG_OBJECT (src, "start connection flush"); + gst_wfdrtspsrc_connection_flush (src, TRUE); + } + + if (src->task) + gst_task_start (src->task); + + GST_OBJECT_UNLOCK (src); +} + +static GstFlowReturn +gst_wfdrtspsrc_loop_udp (GstWFDRTSPSrc * 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_wfdrtspsrc_connection_receive (src, src->conninfo.connection, + &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_wfdrtspsrc_send_keep_alive (src)) == GST_RTSP_EINTR) + goto interrupt; + break; + 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.")); + goto connect_error; + default: + goto receive_error; + } + + switch (message.type) { + case GST_RTSP_MESSAGE_REQUEST: + /* server sends us a request message, handle it */ + res = + gst_wfdrtspsrc_handle_request (src, src->conninfo.connection, + &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"); + if (src->debug) + wfd_rtsp_manager_message_dump (&message); + if (message.type_data.response.code == GST_RTSP_STS_UNAUTHORIZED) { + GST_DEBUG_OBJECT (src, "but is Unauthorized response ..."); + if (gst_wfdrtspsrc_setup_auth (src, &message) && !(retry++)) { + GST_DEBUG_OBJECT (src, "so retrying keep-alive"); + if ((res = gst_wfdrtspsrc_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; + } + } + + /* 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; + GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL), + ("Could not connect to server. (%s)", str)); + g_free (str); + ret = GST_FLOW_ERROR; + + 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 gboolean +gst_wfdrtspsrc_loop (GstWFDRTSPSrc * src) +{ + GstFlowReturn ret; + + if (!src->conninfo.connection || !src->conninfo.connected) + goto no_connection; + + ret = gst_wfdrtspsrc_loop_udp (src); + + if (ret != GST_FLOW_OK) + goto pause; + + return TRUE; + + /* ERRORS */ +no_connection: + { + GST_ERROR_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); + if (ret == GST_FLOW_EOS) { + /* perform EOS logic */ + gst_wfdrtspsrc_push_event (src, gst_event_new_eos (), FALSE); + } 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_ERROR (src, STREAM, FAILED, + ("Internal data flow error."), + ("streaming task paused, reason %s (%d)", reason, ret)); + gst_wfdrtspsrc_push_event (src, gst_event_new_eos (), FALSE); + } + + return FALSE; + } +} + +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"; + default: + break; + } + + return "Unknown"; +} + +static const gchar * +gst_wfdrtspsrc_skip_lws (const gchar * s) +{ + while (g_ascii_isspace (*s)) + s++; + return s; +} + +static const gchar * +gst_wfdrtspsrc_unskip_lws (const gchar * s, const gchar * start) +{ + while (s > start && g_ascii_isspace (*(s - 1))) + s--; + return s; +} + +static const gchar * +gst_wfdrtspsrc_skip_commas (const gchar * s) +{ + /* The grammar allows for multiple commas */ + while (g_ascii_isspace (*s) || *s == ',') + s++; + return s; +} + +static const gchar * +gst_wfdrtspsrc_skip_item (const gchar * s) +{ + gboolean quoted = FALSE; + const gchar *start = s; + + /* A list item ends at the last non-whitespace character + * before a comma which is not inside a quoted-string. Or at + * the end of the string. + */ + while (*s) { + if (*s == '"') + quoted = !quoted; + else if (quoted) { + if (*s == '\\' && *(s + 1)) + s++; + } else { + if (*s == ',') + break; + } + s++; + } + + return gst_wfdrtspsrc_unskip_lws (s, start); +} + +static void +gst_rtsp_decode_quoted_string (gchar * quoted_string) +{ + gchar *src, *dst; + + src = quoted_string + 1; + dst = quoted_string; + while (*src && *src != '"') { + if (*src == '\\' && *(src + 1)) + src++; + *dst++ = *src++; + } + *dst = '\0'; +} + +/* Extract the authentication tokens that the server provided for each method + * into an array of structures and give those to the connection object. + */ +static void +gst_wfdrtspsrc_parse_digest_challenge (GstRTSPConnection * conn, + const gchar * header, gboolean * stale) +{ + GSList *list = NULL, *iter; + const gchar *end; + gchar *item, *eq, *name_end, *value; + + g_return_if_fail (stale != NULL); + + gst_rtsp_connection_clear_auth_params (conn); + *stale = FALSE; + + /* Parse a header whose content is described by RFC2616 as + * "#something", where "something" does not itself contain commas, + * except as part of quoted-strings, into a list of allocated strings. + */ + header = gst_wfdrtspsrc_skip_commas (header); + while (*header) { + end = gst_wfdrtspsrc_skip_item (header); + list = g_slist_prepend (list, g_strndup (header, end - header)); + header = gst_wfdrtspsrc_skip_commas (end); + } + if (!list) + return; + + list = g_slist_reverse (list); + for (iter = list; iter; iter = iter->next) { + item = iter->data; + + if (item == NULL) continue; + + eq = strchr (item, '='); + if (eq) { + name_end = (gchar *) gst_wfdrtspsrc_unskip_lws (eq, item); + if (name_end == item) { + /* That's no good... */ + g_free (item); + item = NULL; + continue; + } + + *name_end = '\0'; + + value = (gchar *) gst_wfdrtspsrc_skip_lws (eq + 1); + if (*value == '"') + gst_rtsp_decode_quoted_string (value); + } else + value = NULL; + + if(value && item) + if ((strcmp (item, "stale") == 0) && (strcmp (value, "TRUE") == 0)) + *stale = TRUE; + gst_rtsp_connection_set_auth_param (conn, item, value); + g_free (item); + } + + g_slist_free (list); +} + +/* 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_wfdrtspsrc_parse_auth_hdr (gchar * hdr, GstRTSPAuthMethod * methods, + GstRTSPConnection * conn, gboolean * stale) +{ + gchar *start; + + g_return_if_fail (hdr != NULL); + g_return_if_fail (methods != NULL); + g_return_if_fail (stale != NULL); + + /* Skip whitespace at the start of the string */ + for (start = hdr; start[0] != '\0' && g_ascii_isspace (start[0]); start++); + + if (g_ascii_strncasecmp (start, "basic", 5) == 0) + *methods |= GST_RTSP_AUTH_BASIC; + else if (g_ascii_strncasecmp (start, "digest ", 7) == 0) { + *methods |= GST_RTSP_AUTH_DIGEST; + gst_wfdrtspsrc_parse_digest_challenge (conn, &start[7], stale); + } +} + +/** + * gst_wfdrtspsrc_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_wfdrtspsrc_setup_auth (GstWFDRTSPSrc * 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; + gchar *hdr; + gboolean stale = FALSE; + + conn = src->conninfo.connection; + + /* Identify the available auth methods and see if any are supported */ + if (gst_rtsp_message_get_header (response, GST_RTSP_HDR_WWW_AUTHENTICATE, + &hdr, 0) == GST_RTSP_OK) { + gst_wfdrtspsrc_parse_auth_hdr (hdr, &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_wfdrtspsrc_try_send (GstWFDRTSPSrc * src, GstRTSPConnection * conn, + GstRTSPMessage * request, GstRTSPMessage * response, + GstRTSPStatusCode * code) +{ + GstRTSPResult res = GST_RTSP_OK; + GstRTSPStatusCode thecode = GST_RTSP_STS_OK; + +again: + gst_wfd_rtsp_ext_list_before_send (src->extensions, request); + + GST_DEBUG_OBJECT (src, "sending message"); + + if (src->debug) + wfd_rtsp_manager_message_dump (request); + + res = gst_wfdrtspsrc_connection_send (src, conn, request, src->ptcp_timeout); + if (res < 0) + goto send_error; + + gst_rtsp_connection_reset_timeout (conn); + +next: + res = gst_wfdrtspsrc_connection_receive (src, conn, response, src->ptcp_timeout); + if (res < 0) + goto receive_error; + + if (src->debug) + wfd_rtsp_manager_message_dump (response); + + switch (response->type) { + case GST_RTSP_MESSAGE_REQUEST: + res = gst_wfdrtspsrc_handle_request (src, conn, response); + if (res == GST_RTSP_EEOF) + goto server_eof; + else if (res < 0) + goto handle_request_failed; + goto next; + case GST_RTSP_MESSAGE_RESPONSE: + /* ok, a response is good */ + GST_DEBUG_OBJECT (src, "received response message"); + break; + default: + case GST_RTSP_MESSAGE_DATA: + /* get next response */ + GST_DEBUG_OBJECT (src, "ignoring data response message"); + goto next; + } + + 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; + + gst_wfd_rtsp_ext_list_after_send (src->extensions, request, response); + + return GST_RTSP_OK; + + /* ERRORS */ +send_error: + { + gchar *str = gst_rtsp_strresult (res); + + GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL), + ("Could not send message. (%s)", str)); + g_free (str); + return res; + } +receive_error: + { + switch (res) { + case GST_RTSP_EEOF: + GST_ERROR_OBJECT (src, "server closed connection, doing reconnect"); +#if 0 + if (try == 0) { + try++; + /* if reconnect succeeds, try again */ + if ((res = gst_wfdrtspsrc_conninfo_reconnect (src, &src->conninfo)) == 0) + goto again; + } +#endif + /* only try once after reconnect, then fallthrough and error out */ + default: + { + gchar *str = gst_rtsp_strresult (res); + + GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), + ("Could not receive message. (%s)", str)); + 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; + } +} + +/** + * gst_wfdrtspsrc_send: + * @src: the rtsp source + * @conn: the connection to send on + * @request: must point to a valid request + * @response: must point to an empty #GstRTSPMessage + * @code: an optional code result + * + * 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_wfdrtspsrc_setup_auth and retry + * the request. + * + * Returns: #GST_RTSP_OK if the processing was successful. + */ + +static GstRTSPResult +gst_wfdrtspsrc_send (GstWFDRTSPSrc * src, GstRTSPConnection * conn, + GstRTSPMessage * request, GstRTSPMessage * response, + GstRTSPStatusCode * code) +{ + GstRTSPStatusCode int_code = GST_RTSP_STS_OK; + GstRTSPResult res = GST_RTSP_ERROR; + gint count; + gboolean retry; + GstRTSPMethod method = GST_RTSP_INVALID; + + 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 ((res = + gst_wfdrtspsrc_try_send (src, conn, request, response, &int_code)) < 0) + goto error; + + switch (int_code) { + case GST_RTSP_STS_UNAUTHORIZED: + if (gst_wfdrtspsrc_setup_auth (src, response)) { + /* Try the request/response again after configuring the auth info + * and loop again */ + retry = TRUE; + } + break; + 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: + GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), ("%s", + response->type_data.response.reason)); + 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; + + GError *err = NULL; + gst_wfdrtspsrc_uri_set_uri (GST_URI_HANDLER (src), new_location, &err); + + /* set old transports */ + if (src->conninfo.url && transports != GST_RTSP_LOWER_TRANS_UNKNOWN) + src->conninfo.url->transports = transports; + + src->need_redirect = TRUE; + src->state = GST_RTSP_STATE_INIT; + 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_ERROR_OBJECT (src, "got NOT IMPLEMENTED, disable method %s", + gst_rtsp_method_as_text (method)); + src->methods &= ~method; + res = GST_RTSP_OK; + break; + default: + GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), + ("Got error response: %d (%s).", response->type_data.response.code, + response->type_data.response.reason)); + 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_wfdrtspsrc_send_cb (GstRTSPExtension * ext, GstRTSPMessage * request, + GstRTSPMessage * response, GstWFDRTSPSrc * src) +{ + return gst_wfdrtspsrc_send (src, src->conninfo.connection, request, response, + 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_wfdrtspsrc_parse_methods (GstWFDRTSPSrc * src, GstRTSPMessage * response) +{ + GstRTSPHeaderField field; + gchar *respoptions; + gchar **options; + gint indx = 0; + gint i; + + /* 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 (indx == 0 && !respoptions) { + /* if no Allow header was found then try the Public header... */ + field = GST_RTSP_HDR_PUBLIC; + gst_rtsp_message_get_header (response, field, &respoptions, indx); + } + if (!respoptions) + break; + + /* If we get here, the server gave a list of supported methods, parse + * them here. The string is like: + * + * OPTIONS, DESCRIBE, ANNOUNCE, PLAY, SETUP, ... + */ + options = g_strsplit (respoptions, ",", 0); + + for (i = 0; options[i]; i++) { + gchar *stripped; + gint method; + + stripped = g_strstrip (options[i]); + method = gst_rtsp_find_method (stripped); + + /* keep bitfield of supported methods */ + if (method != GST_RTSP_INVALID) + src->methods |= method; + } + g_strfreev (options); + + 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; + + if (!(src->methods & GST_RTSP_SETUP)) + goto no_setup; + + return TRUE; + +no_setup: + { + GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), + ("Server does not support SETUP.")); + return FALSE; + } +} + +static GstRTSPResult +gst_wfdrtspsrc_create_transports_string (GstWFDRTSPSrc * src, gchar ** transports) +{ + GstRTSPResult res = GST_RTSP_OK; + GString *result; + + *transports = NULL; + + res = + gst_wfd_rtsp_ext_list_get_transports (src->extensions, GST_RTSP_LOWER_TRANS_UDP, transports); + + if (res < 0) + return GST_RTSP_ERROR; + + GST_DEBUG_OBJECT (src, "got transports %s", GST_STR_NULL (*transports)); + + /* extension listed transports, use those */ + if (*transports != NULL) + return GST_RTSP_OK; + + /* the default RTSP transports */ + result = g_string_new (""); + GST_DEBUG_OBJECT (src, "adding UDP unicast"); + + g_string_append (result, "RTP/AVP"); + g_string_append (result, "/UDP"); + g_string_append (result, ";unicast;client_port="); + g_string_append_printf (result, "%d", src->primary_rtpport); + g_string_append (result, "-"); + g_string_append_printf (result, "%d", src->primary_rtpport+1); + + *transports = g_string_free (result, FALSE); + + GST_DEBUG_OBJECT (src, "prepared transports %s", GST_STR_NULL (*transports)); + + 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. + * + * This function will also configure the manager for the selected transport, + * which basically means creating the pipeline. + */ +static gboolean +gst_wfdrtspsrc_setup (GstWFDRTSPSrc * src) +{ + GstRTSPResult res = GST_RTSP_OK; + GstRTSPMessage request = { 0 }; + GstRTSPMessage response = { 0 }; + WFDRTSPManager *manager = NULL; + GstRTSPLowerTrans protocols = GST_RTSP_LOWER_TRANS_UNKNOWN; + GstRTSPStatusCode code = GST_RTSP_STS_OK; + GstRTSPUrl *url; + gchar *hval; + GstRTSPConnection *conn; + gchar *transports = 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 & GST_RTSP_LOWER_TRANS_UDP; + } else { + url = NULL; + protocols = GST_RTSP_LOWER_TRANS_UDP; + } + + if (protocols == 0) + goto no_protocols; + + manager = src->manager; + + manager->conninfo.location = g_strdup (src->conninfo.location); + GST_DEBUG_OBJECT (src, " setup: %s", + GST_STR_NULL (manager->conninfo.location)); + + manager->control_url = g_strdup (src->conninfo.url_str); + GST_DEBUG_OBJECT (src, " setup: %s", + GST_STR_NULL (manager->control_url)); + + manager->control_connection = src->conninfo.connection; + GST_DEBUG_OBJECT (src, " setup: %p", manager->control_connection); + + /* see if we need to configure this manager */ + if (!gst_wfd_rtsp_ext_list_configure_stream (src->extensions, manager->caps)) { + GST_DEBUG_OBJECT (src, "disabled by extension"); + goto no_setup; + } + + /* skip setup if we have no URL for it */ + if (manager->conninfo.location == NULL) { + GST_DEBUG_OBJECT (src, "no URL for set."); + goto no_setup; + } + + if (src->conninfo.connection == NULL) { + GST_DEBUG_OBJECT (src, "try to connect manager %p", manager); + if (!gst_wfdrtspsrc_conninfo_connect (src, &manager->conninfo)) { + GST_DEBUG_OBJECT (src, "failed to connect %p", manager); + goto no_setup; + } + conn = manager->conninfo.connection; + } else { + conn = src->conninfo.connection; + } + GST_DEBUG_OBJECT (src, "doing setup of manager %p with %s", manager, + manager->conninfo.location); + + /* wfd use only UDP protocol for setup */ + if (!(protocols & GST_RTSP_LOWER_TRANS_UDP)) + goto no_protocols; + + GST_DEBUG_OBJECT (src, "protocols = 0x%x", protocols); + /* create a string with first transport in line */ + res = gst_wfdrtspsrc_create_transports_string (src, &transports); + if (res < 0 || transports == NULL) + goto setup_transport_failed; + + if (strlen (transports) == 0) { + g_free (transports); + GST_DEBUG_OBJECT (src, "no transports found"); + goto setup_transport_failed; + } + + /* create SETUP request */ + res = + gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + manager->conninfo.location); + if (res < 0) { + g_free (transports); + goto create_request_failed; + } + + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_USER_AGENT, (const gchar *)src->user_agent); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, transports); + g_free (transports); + + /* 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_add_header (&request, GST_RTSP_HDR_BLOCKSIZE, hval); + g_free (hval); + } + + /* handle the code ourselves */ + if ((res = gst_wfdrtspsrc_send (src, conn, &request, &response, &code) < 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); + goto no_protocols; + break; + default: + goto response_error; + } + + /* parse response transport */ + { + gchar *resptrans = NULL; + GstRTSPTransport transport = { 0 }; + + gst_rtsp_message_get_header (&response, GST_RTSP_HDR_TRANSPORT, + &resptrans, 0); + if (!resptrans) + goto no_transport; + + /* parse transport, go to next manager on parse error */ + if (gst_rtsp_transport_parse (resptrans, &transport) != GST_RTSP_OK) { + GST_ERROR_OBJECT (src, "failed to parse transport %s", resptrans); + goto setup_failed; + } + + switch (transport.lower_transport) { + case GST_RTSP_LOWER_TRANS_UDP: + protocols = GST_RTSP_LOWER_TRANS_UDP; + break; + case GST_RTSP_LOWER_TRANS_TCP: + case GST_RTSP_LOWER_TRANS_UDP_MCAST: + GST_DEBUG_OBJECT (src, "transport %d is not supported", + transport.lower_transport); + goto setup_failed; + break; + default: + GST_DEBUG_OBJECT (src, "manager %p unknown transport %d", manager, + transport.lower_transport); + goto setup_failed; + break; + } + + /* now configure the manager with the selected transport */ + if (!wfd_rtsp_manager_configure_transport (manager, &transport, + src->primary_rtpport, src->primary_rtpport+1)) { + GST_DEBUG_OBJECT (src, "could not configure transport"); + goto setup_failed; + } + + if(src->manager->enable_pad_probe) { + wfd_rtsp_manager_enable_pad_probe(src->manager); + } + + /* clean up our transport struct */ + gst_rtsp_transport_init (&transport); + /* clean up used RTSP messages */ + gst_rtsp_message_unset (&request); + gst_rtsp_message_unset (&response); + } + + gst_wfd_rtsp_ext_list_stream_select (src->extensions, url); + + return TRUE; + + /* 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 FALSE; + } +no_setup: + { + GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), + ("Could not setup")); + return FALSE; + } +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.")); + 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))); + goto cleanup_error; + } +send_error: + { + gchar *str = gst_rtsp_strresult (res); + + GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL), + ("Could not send message. (%s)", str)); + g_free (str); + goto cleanup_error; + } +no_transport: + { + GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), + ("Server did not select transport.")); + goto cleanup_error; + } +setup_failed: + { + GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), + ("Could not setup.")); + goto cleanup_error; + } +cleanup_error: + { + gst_rtsp_message_unset (&request); + gst_rtsp_message_unset (&response); + return FALSE; + } +} + + +/* Parse all the wifi related messages. + * + * Uses wfdconfig utility to parse the wfd parameters sent from the server + */ + +static GstRTSPResult +gst_wfdrtspsrc_retrieve_wifi_parameters (GstWFDRTSPSrc * src) +{ + GstRTSPResult res = GST_RTSP_OK; + GstRTSPMessage request = { 0 }; + GstRTSPMessage response = { 0 }; + GstRTSPMessage message = { 0 }; + GstRTSPMethod method = { 0 }; + gchar *str = NULL; + gchar *ua = NULL; + + /* can't continue without a valid url */ + if (G_UNLIKELY (src->conninfo.url == NULL)) + goto no_url; + src->tried_url_auth = FALSE; + + if ((res = gst_wfdrtspsrc_conninfo_connect (src, &src->conninfo)) < 0) + goto connect_failed; + + res = gst_wfdrtspsrc_connection_receive (src, src->conninfo.connection, &message, + src->ptcp_timeout); + if(res != GST_RTSP_OK) + goto connect_failed; + + if(message.type == GST_RTSP_MESSAGE_REQUEST) { + method = message.type_data.request.method; + if(method == GST_RTSP_OPTIONS) + gst_wfdrtspsrc_handle_request (src, src->conninfo.connection, &message); + else + goto methods_error; + } + + /* create OPTIONS */ + GST_DEBUG_OBJECT (src, "create options..."); + res = gst_rtsp_message_init_request (&request, GST_RTSP_OPTIONS,"*"); + if (res < 0) + goto create_request_failed; + + str = g_strdup ("org.wfa.wfd1.0"); + ua = g_strdup (src->user_agent); + + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_REQUIRE, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_USER_AGENT, ua); + + if(str) + g_free(str); + str = NULL; + if(ua) + g_free(ua); + ua = NULL; + + /* send OPTIONS */ + GST_DEBUG_OBJECT (src, "send options..."); + if (gst_wfdrtspsrc_send (src, src->conninfo.connection, &request, &response, + NULL) < 0) + goto send_error; + + /* parse OPTIONS */ + if (!gst_wfdrtspsrc_parse_methods (src, &response)) + goto methods_error; + + /* Receive request message from source */ +receive_request_message: + res = gst_wfdrtspsrc_connection_receive (src, src->conninfo.connection, &message, + src->ptcp_timeout); + if(res != GST_RTSP_OK) + goto connect_failed; + + if(message.type == GST_RTSP_MESSAGE_REQUEST) { + method = message.type_data.request.method; + if(method == GST_RTSP_GET_PARAMETER ||method == GST_RTSP_SET_PARAMETER) + gst_wfdrtspsrc_handle_request (src, src->conninfo.connection, &message); + else + goto methods_error; + + if (src->state != GST_RTSP_STATE_READY) + goto receive_request_message; + } + + /* 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: + { + str = NULL; + str = gst_rtsp_strresult (res); + + GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL), + ("Failed to connect. (%s)", str)); + g_free (str); + goto cleanup_error; + } +create_request_failed: + { + str = NULL; + 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: + { + GST_ERROR_OBJECT (src, "method errors"); + /* error was posted */ + goto cleanup_error; + } + +cleanup_error: + { + if (src->conninfo.connection) { + GST_ERROR_OBJECT (src, "free connection"); + gst_wfdrtspsrc_conninfo_close (src, &src->conninfo, TRUE); + } + gst_rtsp_message_unset (&request); + gst_rtsp_message_unset (&response); + return res; + } +} + + + +static GstRTSPResult +gst_wfdrtspsrc_open (GstWFDRTSPSrc * src) +{ + GstRTSPResult res; + + src->methods = + GST_RTSP_SETUP | GST_RTSP_PLAY | GST_RTSP_PAUSE | GST_RTSP_TEARDOWN; + + if ((res = gst_wfdrtspsrc_retrieve_wifi_parameters (src)) < 0) + goto open_failed; + +done: + gst_wfdrtspsrc_loop_end_cmd (src, CMD_OPEN, res); + + return res; + + /* ERRORS */ +open_failed: + { + GST_ERROR_OBJECT (src, "failed to open"); + goto done; + } +} + + +static GstRTSPResult +gst_wfdrtspsrc_close (GstWFDRTSPSrc * src, gboolean only_close) +{ + WFDRTSPManager *manager = NULL; + GstRTSPMessage request = { 0 }; + GstRTSPMessage response = { 0 }; + GstRTSPResult res = GST_RTSP_OK; + gchar *control; + gchar *setup_url; + GstWFDRTSPConnInfo *info; + + GST_DEBUG_OBJECT (src, "TEARDOWN..."); + + 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 = src->conninfo.url_str; + + if (!(src->methods & (GST_RTSP_PLAY | GST_RTSP_TEARDOWN))) + goto not_supported; + + manager = src->manager; + + /* try aggregate control first but do non-aggregate control otherwise */ + if (control) + setup_url = control; + else if ((setup_url = manager->conninfo.location) == NULL) + goto close; + + if (src->conninfo.connection) { + info = &src->conninfo; + } else if (manager->conninfo.connection) { + info = &manager->conninfo; + } else { + goto close; + } + if (!info->connected) + goto close; + + /* do TEARDOWN */ + res = + gst_rtsp_message_init_request (&request, GST_RTSP_TEARDOWN, setup_url); + if (res < 0) + goto create_request_failed; + + if ((res = + gst_wfdrtspsrc_send (src, info->connection, &request, &response, + NULL)) < 0) + goto send_error; + + /* FIXME, parse result? */ + gst_rtsp_message_unset (&request); + gst_rtsp_message_unset (&response); + +close: + /* close connections */ + GST_DEBUG_OBJECT (src, "closing connection..."); + gst_wfdrtspsrc_conninfo_close (src, &src->conninfo, TRUE); + if (manager) { + GST_DEBUG_OBJECT (src, "closing manager %p connection...", manager); + gst_wfdrtspsrc_conninfo_close (src, &manager->conninfo, TRUE); + } + + /* cleanup */ + gst_wfdrtspsrc_cleanup (src); + + src->state = GST_RTSP_STATE_INVALID; + + gst_wfdrtspsrc_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_ERROR_OBJECT (src, "TEARDOWN interrupted"); + } + g_free (str); + goto close; + } +not_supported: + { + GST_ERROR_OBJECT (src, + "TEARDOWN and PLAY not supported, can't do TEARDOWN"); + goto close; + } +} + +/* RTP-Info is of the format: + * + * url=;[seq=;rtptime=] [, 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_wfdrtspsrc_parse_rtpinfo (GstWFDRTSPSrc * 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; + WFDRTSPManager *manager; + gint64 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 */ + manager = NULL; + seqbase = GST_CLOCK_TIME_NONE; + timebase = GST_CLOCK_TIME_NONE; + + /* parse url, find manager 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 manager */ + manager = src->manager; + } 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 manager */ + if (manager != NULL) { + GST_DEBUG_OBJECT (src, + "found manager %p, setting: seqbase %"G_GINT64_FORMAT", timebase %" G_GINT64_FORMAT, + manager, seqbase, timebase); + + /* we have a manager, configure detected params */ + manager->seqbase = seqbase; + manager->timebase = timebase; + } + } + g_strfreev (infos); + + return TRUE; +} + +static GstRTSPResult +gst_wfdrtspsrc_play (GstWFDRTSPSrc * src) +{ + GstRTSPMessage request = { 0 }; + GstRTSPMessage response = { 0 }; + GstRTSPResult res = GST_RTSP_OK; + gchar *hval; + gint hval_idx; + gchar *control; + WFDRTSPManager *manager; + gchar *setup_url; + GstRTSPConnection *conn; + + src->is_paused = FALSE; + + + GST_DEBUG_OBJECT (src, "PLAY..."); + + 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_wfdrtspsrc_send_dummy_packets (src); + + gst_element_set_state (GST_ELEMENT_CAST (src), GST_STATE_PLAYING); + + /* construct a control url */ + control = src->conninfo.url_str; + + manager = src->manager; + /* try aggregate control first but do non-aggregate control otherwise */ + if (control) + setup_url = control; + else if ((setup_url = manager->conninfo.location) == NULL) + goto skip; + + if (src->conninfo.connection) { + conn = src->conninfo.connection; + } else if (manager->conninfo.connection) { + conn = manager->conninfo.connection; + } else { + goto skip; + } + + /* do play */ + res = gst_rtsp_message_init_request (&request, GST_RTSP_PLAY, setup_url); + if (res < 0) + goto create_request_failed; + + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_USER_AGENT, (const gchar*)src->user_agent); + + if ((res = gst_wfdrtspsrc_send (src, conn, &request, &response, NULL)) < 0) + goto send_error; + + gst_rtsp_message_unset (&request); + + /* 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_wfdrtspsrc_parse_rtpinfo (src, hval); + + gst_rtsp_message_unset (&response); + +skip: + /* configure the caps of the streams after we parsed all headers. */ + gst_wfdrtspsrc_configure_caps (src); + + src->state = GST_RTSP_STATE_PLAYING; + + /* mark discont */ + GST_DEBUG_OBJECT (src, "mark DISCONT"); + manager->discont = TRUE; + +done: + gst_wfdrtspsrc_loop_end_cmd (src, CMD_PLAY, res); + + return res; + + /* ERRORS */ +not_supported: + { + GST_ERROR_OBJECT (src, "PLAY is not supported"); + goto done; + } +was_playing: + { + GST_DEBUG_OBJECT (src, "we were already PLAYING"); + goto done; + } +create_request_failed: + { + GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL), + ("Could not create request.")); + return FALSE; + } +send_error: + { + gst_rtsp_message_unset (&request); + GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL), + ("Could not send message.")); + return FALSE; + } +} + +static GstRTSPResult +gst_wfdrtspsrc_pause (GstWFDRTSPSrc * src) +{ + GstRTSPResult res = GST_RTSP_OK; + GstRTSPMessage request = { 0 }; + GstRTSPMessage response = { 0 }; + WFDRTSPManager *manager; + GstRTSPConnection *conn; + gchar *setup_url; + gchar *control; + + GST_DEBUG_OBJECT (src, "PAUSE..."); + + 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 = src->conninfo.url_str; + + manager = src->manager; + + /* try aggregate control first but do non-aggregate control otherwise */ + if (control) + setup_url = control; + else if ((setup_url = manager->conninfo.location) == NULL) + goto no_connection; + + if (src->conninfo.connection) { + conn = src->conninfo.connection; + } else if (manager->conninfo.connection) { + conn = manager->conninfo.connection; + } else { + goto no_connection; + } + + if (gst_rtsp_message_init_request (&request, GST_RTSP_PAUSE, setup_url) < 0) + goto create_request_failed; + + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_USER_AGENT, (const gchar *)src->user_agent); + + if ((res = gst_wfdrtspsrc_send (src, conn, &request, &response, NULL)) < 0) + goto send_error; + + gst_rtsp_message_unset (&request); + gst_rtsp_message_unset (&response); + + src->is_paused = TRUE; + +no_connection: + src->state = GST_RTSP_STATE_READY; + +done: + gst_wfdrtspsrc_loop_end_cmd (src, CMD_PAUSE, res); + + return res; + + /* ERRORS */ +not_supported: + { + GST_ERROR_OBJECT (src, "PAUSE is not supported"); + goto done; + } +was_paused: + { + GST_DEBUG_OBJECT (src, "we were already PAUSED"); + goto done; + } +create_request_failed: + { + GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL), + ("Could not create request.")); + goto done; + } +send_error: + { + gst_rtsp_message_unset (&request); + GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL), + ("Could not send message.")); + goto done; + } +} + +static void +gst_wfdrtspsrc_handle_message (GstBin * bin, GstMessage * message) +{ + GstWFDRTSPSrc *src; + + src = GST_WFDRTSPSRC (bin); + + GST_DEBUG_OBJECT (src, "got %s message from %s", + GST_MESSAGE_TYPE_NAME (message), GST_MESSAGE_SRC_NAME (message)); + + 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")) + GST_DEBUG_OBJECT (bin, "timeout on UDP port"); + + GST_BIN_CLASS (parent_class)->handle_message (bin, message); + break; + } + case GST_MESSAGE_ERROR: + { + WFDRTSPManager *manager; + GstObject *message_src; + gchar* debug = NULL; + GError* error = NULL; + + message_src = GST_MESSAGE_SRC (message); + + gst_message_parse_error (message, &error, &debug); + GST_ERROR_OBJECT (src, "error : %s", error->message); + GST_ERROR_OBJECT (src, "debug : %s", debug); + + if (debug) + g_free (debug); + debug = NULL; + g_error_free (error); + + manager = src->manager; + if (!manager) + goto forward; + + /* we ignore the RTCP udpsrc */ + if (manager->udpsrc[1] == GST_ELEMENT_CAST (message_src)) + goto done; + + forward: + /* fatal but not our message, forward */ + GST_BIN_CLASS (parent_class)->handle_message (bin, message); + break; + done: + gst_message_unref (message); + break; + } + default: + { + GST_BIN_CLASS (parent_class)->handle_message (bin, message); + break; + } + } +} + +/* the thread where everything happens */ +static void +gst_wfdrtspsrc_thread (GstWFDRTSPSrc * src) +{ + gint cmd; + GstRTSPResult ret; + gboolean running = FALSE; + + GST_OBJECT_LOCK (src); + cmd = src->loop_cmd; + src->loop_cmd = CMD_WAIT; + GST_DEBUG_OBJECT (src, "got command %d", cmd); + + /* we got the message command, so ensure communication is possible again */ + gst_wfdrtspsrc_connection_flush (src, FALSE); + + /* we allow these to be interrupted */ + if (cmd == CMD_LOOP || cmd == CMD_CLOSE || cmd == CMD_PAUSE) + src->waiting = TRUE; + GST_OBJECT_UNLOCK (src); + + switch (cmd) { + case CMD_OPEN: + ret = gst_wfdrtspsrc_open (src); + break; + case CMD_PLAY: + ret = gst_wfdrtspsrc_play (src); + if (ret == GST_RTSP_OK) + running = TRUE; + break; + case CMD_PAUSE: + ret = gst_wfdrtspsrc_pause (src); + if (ret == GST_RTSP_OK) + running = TRUE; + break; + case CMD_CLOSE: + ret = gst_wfdrtspsrc_close (src, FALSE); + break; + case CMD_LOOP: + running = gst_wfdrtspsrc_loop (src); + break; + default: + break; + } + + GST_OBJECT_LOCK (src); + /* and go back to sleep */ + if (src->loop_cmd == CMD_WAIT) { + if (running) + src->loop_cmd = CMD_LOOP; + else if (src->task) + gst_task_pause (src->task); + } + + /* reset waiting */ + src->waiting = FALSE; + GST_OBJECT_UNLOCK (src); +} + +static gboolean +gst_wfdrtspsrc_start (GstWFDRTSPSrc * src) +{ + GST_DEBUG_OBJECT (src, "starting"); + + GST_OBJECT_LOCK (src); + + src->loop_cmd = CMD_WAIT; + + if (src->task == NULL) { + src->task = gst_task_new ((GstTaskFunction) gst_wfdrtspsrc_thread, src, NULL); + if (src->task == NULL) + goto task_error; + + gst_task_set_lock (src->task, GST_WFD_RTSP_TASK_GET_LOCK (src)); + } + GST_OBJECT_UNLOCK (src); + + return TRUE; + + /* ERRORS */ +task_error: + { + GST_ERROR_OBJECT (src, "failed to create task"); + return FALSE; + } +} + +static gboolean +gst_wfdrtspsrc_stop (GstWFDRTSPSrc * src) +{ + GstTask *task; + + GST_DEBUG_OBJECT (src, "stopping"); + + GST_OBJECT_LOCK (src); + GST_DEBUG_OBJECT (src, "interrupt all command"); + src->waiting = TRUE; + src->do_stop = TRUE; + GST_OBJECT_UNLOCK (src); + + /* also cancels pending task */ + gst_wfdrtspsrc_loop_send_cmd (src, CMD_WAIT); + + 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_WFD_RTSP_TASK_LOCK (src); + GST_WFD_RTSP_TASK_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_wfdrtspsrc_close (src, TRUE); + + return TRUE; +} + + +static GstStateChangeReturn +gst_wfdrtspsrc_change_state (GstElement * element, GstStateChange transition) +{ + GstWFDRTSPSrc *src; + GstStateChangeReturn ret; + + src = GST_WFDRTSPSRC (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + GST_DEBUG_OBJECT (src, "NULL->READY"); + if (!gst_wfdrtspsrc_start (src)) + goto start_failed; + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + GST_DEBUG_OBJECT (src, "READY->PAUSED"); + gst_wfdrtspsrc_loop_send_cmd (src, CMD_OPEN); + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + GST_DEBUG_OBJECT(src, "PAUSED->PLAYING"); + gst_wfdrtspsrc_loop_send_cmd (src, CMD_WAIT); + break; + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + GST_DEBUG_OBJECT(src, "PLAYING->PAUSED"); + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + GST_DEBUG_OBJECT(src, "PAUSED->READY"); + break; + case GST_STATE_CHANGE_READY_TO_NULL: + GST_DEBUG_OBJECT (src, "READY->NULL"); + 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_PLAYING: + gst_wfdrtspsrc_loop_send_cmd (src, CMD_PLAY); + break; + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + case GST_STATE_CHANGE_READY_TO_PAUSED: + ret = GST_STATE_CHANGE_NO_PREROLL; + break; + case GST_STATE_CHANGE_READY_TO_NULL: + gst_wfdrtspsrc_stop (src); + break; + default: + break; + } + +done: + GST_DEBUG_OBJECT (src, "state change is done"); + return ret; + +start_failed: + { + GST_ERROR_OBJECT (src, "start failed"); + return GST_STATE_CHANGE_FAILURE; + } +} + +static gboolean +gst_wfdrtspsrc_send_event (GstElement * element, GstEvent * event) +{ + gboolean res; + GstWFDRTSPSrc *src; + + src = GST_WFDRTSPSRC (element); + + if (GST_EVENT_IS_DOWNSTREAM (event)) { + res = gst_wfdrtspsrc_push_event (src, event, TRUE); + } else { + res = GST_ELEMENT_CLASS (parent_class)->send_event (element, event); + } + + return res; +} + + +/*** GSTURIHANDLER INTERFACE *************************************************/ +static GstURIType +gst_wfdrtspsrc_uri_get_type (GType type) +{ + return GST_URI_SRC; +} + +static const gchar * const * +gst_wfdrtspsrc_uri_get_protocols (GType type) +{ + static const gchar *protocols[] = + { "rtsp", NULL }; + + return protocols; +} + +static gchar * +gst_wfdrtspsrc_uri_get_uri (GstURIHandler * handler) +{ + GstWFDRTSPSrc *src = GST_WFDRTSPSRC (handler); + + /* should not dup */ + return src->conninfo.location; +} + +static gboolean +gst_wfdrtspsrc_uri_set_uri (GstURIHandler * handler, const gchar * uri, GError **error) +{ + GstWFDRTSPSrc *src; + GstRTSPResult res; + GstRTSPUrl *newurl = NULL; + + src = GST_WFDRTSPSRC (handler); + + /* same URI, we're fine */ + if (src->conninfo.location && uri && !strcmp (uri, src->conninfo.location)) + goto was_ok; + + /* 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; + + 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; + } +parse_error: + { + GST_ERROR_OBJECT (src, "Not a valid RTSP url '%s' (%d)", + GST_STR_NULL (uri), res); + return FALSE; + } +} + +static void +gst_wfdrtspsrc_uri_handler_init (gpointer g_iface, gpointer iface_data) +{ + GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; + + iface->get_type = gst_wfdrtspsrc_uri_get_type; + iface->get_protocols = gst_wfdrtspsrc_uri_get_protocols; + iface->get_uri = gst_wfdrtspsrc_uri_get_uri; + iface->set_uri = gst_wfdrtspsrc_uri_set_uri; +} + +static gboolean +gst_wfdrtspsrc_plugin_init (GstPlugin *plugin) +{ + if (!gst_element_register (plugin, "wfdrtspsrc", GST_RANK_PRIMARY, gst_wfdrtspsrc_get_type())) { + return FALSE; + } + return TRUE; +} + +static GstRTSPResult _get_cea_resolution_and_set_to_src(GstWFDRTSPSrc *src, WFDVideoCEAResolution Resolution) +{ + WFDVideoCEAResolution CEARes = Resolution; + switch(CEARes) + { + case WFD_CEA_UNKNOWN: + break; + case WFD_CEA_640x480P60: + src->video_width=640; + src->video_height=480; + src->video_framerate=60; + break; + case WFD_CEA_720x480P60: + src->video_width=720; + src->video_height=480; + src->video_framerate=60; + break; + case WFD_CEA_720x480I60: + src->video_width=720; + src->video_height=480; + src->video_framerate=60; + break; + case WFD_CEA_720x576P50: + src->video_width=720; + src->video_height=576; + src->video_framerate=50; + break; + case WFD_CEA_720x576I50: + src->video_width=720; + src->video_height=576; + src->video_framerate=50; + break; + case WFD_CEA_1280x720P30: + src->video_width=1280; + src->video_height=720; + src->video_framerate=30; + break; + case WFD_CEA_1280x720P60: + src->video_width=1280; + src->video_height=720; + src->video_framerate=60; + break; + case WFD_CEA_1920x1080P30: + src->video_width=1920; + src->video_height=1080; + src->video_framerate=30; + break; + case WFD_CEA_1920x1080P60: + src->video_width=1920; + src->video_height=1080; + src->video_framerate=60; + break; + case WFD_CEA_1920x1080I60: + src->video_width=1920; + src->video_height=1080; + src->video_framerate=60; + break; + case WFD_CEA_1280x720P25: + src->video_width=1280; + src->video_height=720; + src->video_framerate=25; + break; + case WFD_CEA_1280x720P50: + src->video_width=1280; + src->video_height=720; + src->video_framerate=50; + break; + case WFD_CEA_1920x1080P25: + src->video_width=1920; + src->video_height=1080; + src->video_framerate=25; + break; + case WFD_CEA_1920x1080P50: + src->video_width=1920; + src->video_height=1080; + src->video_framerate=50; + break; + case WFD_CEA_1920x1080I50: + src->video_width=1920; + src->video_height=1080; + src->video_framerate=50; + break; + case WFD_CEA_1280x720P24: + src->video_width=1280; + src->video_height=720; + src->video_framerate=24; + break; + case WFD_CEA_1920x1080P24: + src->video_width=1920; + src->video_height=1080; + src->video_framerate=24; + break; + default: + break; + } + return GST_RTSP_OK; +} + +static GstRTSPResult _get_vesa_resolution_and_set_to_src(GstWFDRTSPSrc *src, WFDVideoVESAResolution Resolution) +{ + WFDVideoVESAResolution VESARes = Resolution; + switch(VESARes) + { + case WFD_VESA_UNKNOWN: + break; + case WFD_VESA_800x600P30: + src->video_width=800; + src->video_height=600; + src->video_framerate=30; + break; + case WFD_VESA_800x600P60: + src->video_width=800; + src->video_height=600; + src->video_framerate=60; + break; + case WFD_VESA_1024x768P30: + src->video_width=1024; + src->video_height=768; + src->video_framerate=30; + break; + case WFD_VESA_1024x768P60: + src->video_width=1024; + src->video_height=768; + src->video_framerate=60; + break; + case WFD_VESA_1152x864P30: + src->video_width=1152; + src->video_height=864; + src->video_framerate=30; + break; + case WFD_VESA_1152x864P60: + src->video_width=1152; + src->video_height=864; + src->video_framerate=60; + break; + case WFD_VESA_1280x768P30: + src->video_width=1280; + src->video_height=768; + src->video_framerate=30; + break; + case WFD_VESA_1280x768P60: + src->video_width=1280; + src->video_height=768; + src->video_framerate=60; + break; + case WFD_VESA_1280x800P30: + src->video_width=1280; + src->video_height=800; + src->video_framerate=30; + break; + case WFD_VESA_1280x800P60: + src->video_width=1280; + src->video_height=800; + src->video_framerate=60; + break; + case WFD_VESA_1360x768P30: + src->video_width=1360; + src->video_height=768; + src->video_framerate=30; + break; + case WFD_VESA_1360x768P60: + src->video_width=1360; + src->video_height=768; + src->video_framerate=60; + break; + case WFD_VESA_1366x768P30: + src->video_width=1366; + src->video_height=768; + src->video_framerate=30; + break; + case WFD_VESA_1366x768P60: + src->video_width=1366; + src->video_height=768; + src->video_framerate=60; + break; + case WFD_VESA_1280x1024P30: + src->video_width=1280; + src->video_height=1024; + src->video_framerate=30; + break; + case WFD_VESA_1280x1024P60: + src->video_width=1280; + src->video_height=1024; + src->video_framerate=60; + break; + case WFD_VESA_1400x1050P30: + src->video_width=1400; + src->video_height=1050; + src->video_framerate=30; + break; + case WFD_VESA_1400x1050P60: + src->video_width=1400; + src->video_height=1050; + src->video_framerate=60; + break; + case WFD_VESA_1440x900P30: + src->video_width=1440; + src->video_height=900; + src->video_framerate=30; + break; + case WFD_VESA_1440x900P60: + src->video_width=1440; + src->video_height=900; + src->video_framerate=60; + break; + case WFD_VESA_1600x900P30: + src->video_width=1600; + src->video_height=900; + src->video_framerate=30; + break; + case WFD_VESA_1600x900P60: + src->video_width=1600; + src->video_height=900; + src->video_framerate=60; + break; + case WFD_VESA_1600x1200P30: + src->video_width=1600; + src->video_height=1200; + src->video_framerate=30; + break; + case WFD_VESA_1600x1200P60: + src->video_width=1600; + src->video_height=1200; + src->video_framerate=60; + break; + case WFD_VESA_1680x1024P30: + src->video_width=1680; + src->video_height=1024; + src->video_framerate=30; + break; + case WFD_VESA_1680x1024P60: + src->video_width=1680; + src->video_height=1024; + src->video_framerate=60; + break; + case WFD_VESA_1680x1050P30: + src->video_width=1680; + src->video_height=1050; + src->video_framerate=30; + break; + case WFD_VESA_1680x1050P60: + src->video_width=1680; + src->video_height=1050; + src->video_framerate=60; + break; + case WFD_VESA_1920x1200P30: + src->video_width=1920; + src->video_height=1200; + src->video_framerate=30; + break; + case WFD_VESA_1920x1200P60: + src->video_width=1920; + src->video_height=1200; + src->video_framerate=60; + break; + default: + break; + } + return GST_RTSP_OK; +} + +static GstRTSPResult _get_hh_resolution_and_set_to_src(GstWFDRTSPSrc *src, WFDVideoHHResolution Resolution) +{ + WFDVideoHHResolution HHRes = Resolution; + switch(HHRes) + { + case WFD_HH_UNKNOWN: + break; + case WFD_HH_800x480P30: + src->video_width=800; + src->video_height=480; + src->video_framerate=30; + break; + case WFD_HH_800x480P60: + src->video_width=800; + src->video_height=480; + src->video_framerate=60; + break; + case WFD_HH_854x480P30: + src->video_width=854; + src->video_height=480; + src->video_framerate=30; + break; + case WFD_HH_854x480P60: + src->video_width=854; + src->video_height=480; + src->video_framerate=60; + break; + case WFD_HH_864x480P30: + src->video_width=864; + src->video_height=480; + src->video_framerate=30; + break; + case WFD_HH_864x480P60: + src->video_width=864; + src->video_height=480; + src->video_framerate=60; + break; + case WFD_HH_640x360P30: + src->video_width=640; + src->video_height=360; + src->video_framerate=30; + break; + case WFD_HH_640x360P60: + src->video_width=640; + src->video_height=360; + src->video_framerate=60; + break; + case WFD_HH_960x540P30: + src->video_width=960; + src->video_height=540; + src->video_framerate=30; + break; + case WFD_HH_960x540P60: + src->video_width=960; + src->video_height=540; + src->video_framerate=60; + break; + case WFD_HH_848x480P30: + src->video_width=848; + src->video_height=480; + src->video_framerate=30; + break; + case WFD_HH_848x480P60: + src->video_width=848; + src->video_height=480; + src->video_framerate=60; + break; + default: + break; + } + return GST_RTSP_OK; +} + +static GstRTSPResult +gst_wfdrtspsrc_get_audio_parameter(GstWFDRTSPSrc * src, WFDMessage * msg) +{ + WFDAudioFormats audio_format = WFD_AUDIO_UNKNOWN; + WFDAudioChannels audio_channels = WFD_CHANNEL_UNKNOWN; + WFDAudioFreq audio_frequency = WFD_FREQ_UNKNOWN; + guint audio_bitwidth = 0; + guint32 audio_latency = 0; + + wfdconfig_get_prefered_audio_format (msg, &audio_format, &audio_frequency, &audio_channels, &audio_bitwidth, &audio_latency); + + src->audio_format = g_strdup(msg->audio_codecs->list->audio_format); + if(audio_frequency == WFD_FREQ_48000) + audio_frequency = 48000; + else if(audio_frequency == WFD_FREQ_44100) + audio_frequency = 44100; + + if(audio_channels == WFD_CHANNEL_2) + audio_channels = 2; + else if(audio_channels == WFD_CHANNEL_4) + audio_channels = 4; + else if(audio_channels == WFD_CHANNEL_6) + audio_channels = 6; + else if(audio_channels == WFD_CHANNEL_8) + audio_channels = 8; + + src->audio_channels = audio_channels; + src->audio_frequency = audio_frequency; + src->audio_bitwidth = audio_bitwidth; + + return GST_RTSP_OK; +} + +static GstRTSPResult +gst_wfdrtspsrc_get_video_parameter(GstWFDRTSPSrc * src, WFDMessage * msg) +{ + WFDVideoCodecs cvCodec = WFD_VIDEO_UNKNOWN; + WFDVideoNativeResolution cNative = WFD_VIDEO_CEA_RESOLUTION; + guint64 cNativeResolution = 0; + WFDVideoCEAResolution cCEAResolution = WFD_CEA_UNKNOWN; + WFDVideoVESAResolution cVESAResolution = WFD_VESA_UNKNOWN; + WFDVideoHHResolution cHHResolution = WFD_HH_UNKNOWN; + WFDVideoH264Profile cProfile = WFD_H264_UNKNOWN_PROFILE; + WFDVideoH264Level cLevel = WFD_H264_LEVEL_UNKNOWN; + guint32 cMaxHeight = 0; + guint32 cMaxWidth = 0; + guint32 cmin_slice_size = 0; + guint32 cslice_enc_params = 0; + guint cframe_rate_control = 0; + guint cvLatency = 0; + wfdconfig_get_prefered_video_format(msg, &cvCodec, &cNative, &cNativeResolution, + &cCEAResolution, &cVESAResolution, &cHHResolution, + &cProfile, &cLevel, &cvLatency, &cMaxHeight, + &cMaxWidth, &cmin_slice_size, &cslice_enc_params, &cframe_rate_control); + switch(cNative) + { + case WFD_VIDEO_CEA_RESOLUTION: + _get_cea_resolution_and_set_to_src(src, cCEAResolution); + break; + case WFD_VIDEO_VESA_RESOLUTION: + _get_vesa_resolution_and_set_to_src(src, cVESAResolution); + break; + case WFD_VIDEO_HH_RESOLUTION: + _get_hh_resolution_and_set_to_src(src, cHHResolution); + break; + default: + break; + } + return GST_RTSP_OK; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + wfdrtspsrc, + "Wifi direct src plugin", + gst_wfdrtspsrc_plugin_init, + VERSION, + "LGPL", + "Samsung Electronics Co", + "http://www.samsung.com") + diff --git a/wfdrtspsrc/src/gstwfdrtspsrc.h b/wfdrtspsrc/src/gstwfdrtspsrc.h new file mode 100755 index 0000000..6f26589 --- /dev/null +++ b/wfdrtspsrc/src/gstwfdrtspsrc.h @@ -0,0 +1,187 @@ +/* + * wfdrtspsrc + * + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * 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. + */ + + + +#ifndef __GST_WFDRTSPSRC_H__ +#define __GST_WFDRTSPSRC_H__ + +#include + +G_BEGIN_DECLS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gstwfdrtspext.h" +#include "wfdrtspmanager.h" + +#define GST_TYPE_WFDRTSPSRC \ + (gst_wfdrtspsrc_get_type()) +#define GST_WFDRTSPSRC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WFDRTSPSRC,GstWFDRTSPSrc)) +#define GST_WFDRTSPSRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WFDRTSPSRC,GstWFDRTSPSrcClass)) +#define GST_IS_WFDRTSPSRC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WFDRTSPSRC)) +#define GST_IS_WFDRTSPSRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WFDRTSPSRC)) +#define GST_WFDRTSPSRC_CAST(obj) \ + ((GstWFDRTSPSrc *)(obj)) + +typedef struct _GstWFDRTSPSrc GstWFDRTSPSrc; +typedef struct _GstWFDRTSPSrcClass GstWFDRTSPSrcClass; +typedef struct _GstWFDRTSPSrcPrivate GstWFDRTSPSrcPrivate; + +#define GST_WFD_RTSP_TASK_GET_LOCK(wfd) (GST_WFDRTSPSRC_CAST(wfd)->task_rec_lock) +#define GST_WFD_RTSP_TASK_LOCK(wfd) (g_rec_mutex_lock (GST_WFD_RTSP_TASK_GET_LOCK(wfd))) +#define GST_WFD_RTSP_TASK_UNLOCK(wfd) (g_rec_mutex_unlock (GST_WFD_RTSP_TASK_GET_LOCK(wfd))) + +/** + * GstWFDRTSPNatMethod: + * @GST_WFD_RTSP_NAT_NONE: none + * @GST_WFD_RTSP_NAT_DUMMY: send dummy packets + * + * Different methods for trying to traverse firewalls. + */ +typedef enum +{ + GST_WFD_RTSP_NAT_NONE, + GST_WFD_RTSP_NAT_DUMMY +} GstWFDRTSPNatMethod; + +typedef enum +{ + WFD_ROUTE, + WFD_CONNECTOR_TYPE, + WFD_STANDBY, + WFD_IDR_REQUEST, + WFD_UIBC_CAPABILITY, + WFD_UIBC_SETTING, + WFD_SINK_STATUS +} GstWFDParam; + +struct _GstWFDRTSPSrc { + GstBin parent; + + WFDRTSPManager *manager; + + /* task and mutex */ + GstTask *task; + GRecMutex *task_rec_lock; + gint loop_cmd; + gboolean waiting; + gboolean do_stop; + + /* properties */ + GstRTSPLowerTrans protocols; + gboolean debug; + guint retry; + GTimeVal tcp_timeout; + GTimeVal *ptcp_timeout; + GstWFDRTSPNatMethod nat_method; + gchar *proxy_host; + guint proxy_port; + gchar *proxy_user; + gchar *proxy_passwd; + guint rtp_blocksize; + gchar *user_id; + gchar *user_pw; + GstStructure *audio_param; + GstStructure *video_param; + GstStructure *hdcp_param; + /* Set User-agent */ + gchar *user_agent; + /* Set RTP port */ + gint primary_rtpport; + gint secondary_rtpport; + + /* state */ + GstRTSPState state; + gboolean tried_url_auth; + gboolean need_redirect; + + /* supported methods */ + gint methods; + + GstWFDRTSPConnInfo conninfo; + + /* a list of RTSP extensions as GstElement */ + GstWFDRTSPExtensionList *extensions; + + + GTimeVal ssr_timeout; + guint video_height; + guint video_width; + guint video_framerate; + gchar * audio_format; + guint audio_channels; + guint audio_bitwidth; + guint audio_frequency; + + gboolean is_paused; +}; + +struct _GstWFDRTSPSrcClass { + GstBinClass parent_class; + + /* signals */ + void (*update_media_info) (GstWFDRTSPSrc *src, GstStructure * str); +}; + +GType gst_wfdrtspsrc_get_type(void); + +G_END_DECLS + +#endif /* __GST_WFDRTSPSRC_H__ */ diff --git a/wfdrtspsrc/src/wfdrtspmanager.c b/wfdrtspsrc/src/wfdrtspmanager.c new file mode 100755 index 0000000..db72fac --- /dev/null +++ b/wfdrtspsrc/src/wfdrtspmanager.c @@ -0,0 +1,1184 @@ +/* + * wfdrtspsrcmanager + * + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * 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 + +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "wfdrtspmanager.h" + +#ifdef G_OS_WIN32 +#include +#endif + +GST_DEBUG_CATEGORY_STATIC (wfd_rtsp_manager_debug); +#define GST_CAT_DEFAULT wfd_rtsp_manager_debug + +/* signals and args */ +enum +{ + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_DO_RTCP, + PROP_LATENCY, + PROP_UDP_BUFFER_SIZE, + PROP_UDP_TIMEOUT, + PROP_ENABLE_PAD_PROBE, + PROP_LAST +}; + +#define DEFAULT_DO_RTCP TRUE +#define DEFAULT_LATENCY_MS 2000 +#define DEFAULT_UDP_BUFFER_SIZE 0x80000 +#define DEFAULT_UDP_TIMEOUT 5000000 + + +G_DEFINE_TYPE (WFDRTSPManager, wfd_rtsp_manager, G_TYPE_OBJECT); + +/* GObject vmethods */ +static void wfd_rtsp_manager_finalize (GObject * object); +static void wfd_rtsp_manager_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void wfd_rtsp_manager_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +GstPadProbeReturn +wfd_rtsp_manager_pad_probe_cb(GstPad * pad, GstPadProbeInfo *info, gpointer u_data); + +/*rtsp dump code start*/ +typedef struct _RTSPKeyValue +{ + GstRTSPHeaderField field; + gchar *value; +} RTSPKeyValue; + + +static void +wfd_rtsp_manager_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 +wfd_rtsp_manager_dump_key_value (gpointer data, gpointer user_data G_GNUC_UNUSED) +{ + RTSPKeyValue *key_value = (RTSPKeyValue *) data; + + GST_ERROR (" key: '%s', value: '%s'", + gst_rtsp_header_as_text (key_value->field), key_value->value); +} + +GstRTSPResult +wfd_rtsp_manager_message_dump (GstRTSPMessage * msg) +{ + guint8 *data; + guint size; + + g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL); + + GST_ERROR("------------------------------------------------------"); + switch (msg->type) { + case GST_RTSP_MESSAGE_REQUEST: + GST_ERROR ("RTSP request message %p", msg); + GST_ERROR (" request line:"); + GST_ERROR (" method: '%s'", + gst_rtsp_method_as_text (msg->type_data.request.method)); + GST_ERROR (" uri: '%s'", msg->type_data.request.uri); + GST_ERROR (" version: '%s'", + gst_rtsp_version_as_text (msg->type_data.request.version)); + GST_ERROR (" headers:"); + wfd_rtsp_manager_key_value_foreach (msg->hdr_fields, wfd_rtsp_manager_dump_key_value, NULL); + GST_ERROR (" body:"); + gst_rtsp_message_get_body (msg, &data, &size); + //gst_util_dump_mem (data, size); + if (size > 0) GST_ERROR ("%s(%d)", data, size); + break; + case GST_RTSP_MESSAGE_RESPONSE: + GST_ERROR ("RTSP response message %p", msg); + GST_ERROR (" status line:"); + GST_ERROR (" code: '%d'", msg->type_data.response.code); + GST_ERROR (" reason: '%s'", msg->type_data.response.reason); + GST_ERROR (" version: '%s'", + gst_rtsp_version_as_text (msg->type_data.response.version)); + GST_ERROR (" headers:"); + wfd_rtsp_manager_key_value_foreach (msg->hdr_fields, wfd_rtsp_manager_dump_key_value, NULL); + gst_rtsp_message_get_body (msg, &data, &size); + GST_ERROR (" body: length %d", size); + //gst_util_dump_mem (data, size); + if (size > 0) GST_ERROR ("%s(%d)", data, size); + break; + case GST_RTSP_MESSAGE_HTTP_REQUEST: + GST_ERROR ("HTTP request message %p", msg); + GST_ERROR (" request line:"); + GST_ERROR (" method: '%s'", + gst_rtsp_method_as_text (msg->type_data.request.method)); + GST_ERROR (" uri: '%s'", msg->type_data.request.uri); + GST_ERROR (" version: '%s'", + gst_rtsp_version_as_text (msg->type_data.request.version)); + GST_ERROR (" headers:"); + wfd_rtsp_manager_key_value_foreach (msg->hdr_fields, wfd_rtsp_manager_dump_key_value, NULL); + GST_ERROR (" body:"); + gst_rtsp_message_get_body (msg, &data, &size); + //gst_util_dump_mem (data, size); + if (size > 0) GST_ERROR ("%s(%d)", data, size); + break; + case GST_RTSP_MESSAGE_HTTP_RESPONSE: + GST_ERROR ("HTTP response message %p", msg); + GST_ERROR (" status line:"); + GST_ERROR (" code: '%d'", msg->type_data.response.code); + GST_ERROR (" reason: '%s'", msg->type_data.response.reason); + GST_ERROR (" version: '%s'", + gst_rtsp_version_as_text (msg->type_data.response.version)); + GST_ERROR (" headers:"); + wfd_rtsp_manager_key_value_foreach (msg->hdr_fields, wfd_rtsp_manager_dump_key_value, NULL); + gst_rtsp_message_get_body (msg, &data, &size); + GST_ERROR (" body: length %d", size); + //gst_util_dump_mem (data, size); + if (size > 0) GST_ERROR ("%s(%d)", data, size); + break; + case GST_RTSP_MESSAGE_DATA: + GST_ERROR ("RTSP data message %p", msg); + GST_ERROR (" channel: '%d'", msg->type_data.data.channel); + GST_ERROR (" size: '%d'", msg->body_size); + gst_rtsp_message_get_body (msg, &data, &size); + //gst_util_dump_mem (data, size); + if (size > 0) GST_ERROR ("%s(%d)", data, size); + break; + default: + GST_ERROR ("unsupported message type %d", msg->type); + return GST_RTSP_EINVAL; + } + + GST_ERROR("------------------------------------------------------"); + return GST_RTSP_OK; +} +/*rtsp dump code end*/ + +static void +wfd_rtsp_manager_class_init (WFDRTSPManagerClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass *) klass; + + gobject_class->finalize = wfd_rtsp_manager_finalize; + gobject_class->set_property = wfd_rtsp_manager_set_property; + gobject_class->get_property = wfd_rtsp_manager_get_property; + + 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)); + + 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_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)); + + g_object_class_install_property (gobject_class, PROP_UDP_TIMEOUT, + g_param_spec_uint64 ("timeout", "UDP Timeout", + "Fail after timeout microseconds on UDP connections (0 = disabled)", + 0, G_MAXUINT64, DEFAULT_UDP_TIMEOUT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_ENABLE_PAD_PROBE, + g_param_spec_boolean ("enable-pad-probe", "Enable Pad Probe", + "Enable pad probe for debugging", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + GST_DEBUG_CATEGORY_INIT (wfd_rtsp_manager_debug, "wfdrtspmanager", 0, "WFD RTSP Manager"); +} + +static void +wfd_rtsp_manager_init (WFDRTSPManager * manager) +{ + GstStructure *s = NULL; + + /* initialize variables */ + manager->do_rtcp = DEFAULT_DO_RTCP; + manager->latency = DEFAULT_LATENCY_MS; + manager->udp_buffer_size = DEFAULT_UDP_BUFFER_SIZE; + manager->udp_timeout = DEFAULT_UDP_TIMEOUT; + manager->enable_pad_probe = FALSE; + + manager->eos = FALSE; + manager->discont = TRUE; + manager->seqbase = GST_CLOCK_TIME_NONE; + manager->timebase = GST_CLOCK_TIME_NONE; + manager->is_ipv6 = FALSE; + manager->caps = gst_caps_new_simple ("application/x-rtp", + "media", G_TYPE_STRING, "video", "payload", G_TYPE_INT, 33, NULL); + + s = gst_caps_get_structure (manager->caps, 0); + gst_structure_set (s, "clock-rate", G_TYPE_INT, 90000, NULL); + gst_structure_set (s, "encoding-params", G_TYPE_STRING, "MP2T-ES", NULL); + + manager->state_rec_lock = g_new (GStaticRecMutex, 1); + g_static_rec_mutex_init (manager->state_rec_lock); + + manager->protocol = GST_RTSP_LOWER_TRANS_UDP; +} + + +static void +wfd_rtsp_manager_finalize (GObject * object) +{ + WFDRTSPManager *manager; + gint i; + + GST_INFO ("finalize"); + manager = WFD_RTSP_MANAGER_CAST (object); + + if (manager->caps) + gst_caps_unref (manager->caps); + manager->caps = NULL; + + if (manager->conninfo.location) + g_free (manager->conninfo.location); + manager->conninfo.location = NULL; + + for (i=0; i <1; i++) { + if (manager->udpsrc[i]) { + gst_element_set_state (manager->udpsrc[i], GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (manager->wfdrtspsrc), manager->udpsrc[i]); + gst_object_unref (manager->udpsrc[i]); + manager->udpsrc[i] = NULL; + } + if (manager->channelpad[i]) { + gst_object_unref (manager->channelpad[i]); + manager->channelpad[i] = NULL; + } + if (manager->udpsink[i]) { + gst_element_set_state (manager->udpsink[i], GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (manager->wfdrtspsrc), manager->udpsink[i]); + gst_object_unref (manager->udpsink[i]); + manager->udpsink[i] = NULL; + } + } + if (manager->requester) { + gst_element_set_state (manager->requester, GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (manager->wfdrtspsrc), manager->requester); + gst_object_unref (manager->requester); + manager->requester = NULL; + } + + if (manager->session) { + gst_element_set_state (manager->session, GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (manager->wfdrtspsrc), manager->session); + gst_object_unref (manager->session); + manager->session = NULL; + } + if (manager->jitterbuffer) { + gst_element_set_state (manager->jitterbuffer, GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (manager->wfdrtspsrc), manager->jitterbuffer); + gst_object_unref (manager->jitterbuffer); + manager->jitterbuffer = NULL; + } + if (manager->fakesrc) { + gst_element_set_state (manager->fakesrc, GST_STATE_NULL); + gst_bin_remove (GST_BIN_CAST (manager->wfdrtspsrc), manager->fakesrc); + gst_object_unref (manager->fakesrc); + manager->fakesrc = NULL; + } + if (manager->srcpad) { + gst_pad_set_active (manager->srcpad, FALSE); + gst_element_remove_pad (GST_ELEMENT_CAST (manager->wfdrtspsrc), manager->srcpad); + manager->srcpad = NULL; + } + if (manager->rtcppad) { + gst_object_unref (manager->rtcppad); + manager->rtcppad = NULL; + } + g_static_rec_mutex_free (manager->state_rec_lock); + g_free (manager->state_rec_lock); + + G_OBJECT_CLASS (wfd_rtsp_manager_parent_class)->finalize (object); +} + + +WFDRTSPManager * +wfd_rtsp_manager_new (GstElement *wfdrtspsrc) +{ + WFDRTSPManager *manager; + + g_return_val_if_fail (wfdrtspsrc, NULL); + g_return_val_if_fail (GST_IS_ELEMENT(wfdrtspsrc), NULL); + + manager = g_object_new (WFD_TYPE_RTSP_MANAGER, NULL); + if (G_UNLIKELY(!manager)) { + GST_ERROR("failed to create Wi-Fi Display manager."); + return NULL; + } + + manager->wfdrtspsrc = wfdrtspsrc; + + return manager; +} + +static void +wfd_rtsp_manager_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + WFDRTSPManager *manager; + + manager = WFD_RTSP_MANAGER_CAST (object); + + switch (prop_id) { + case PROP_DO_RTCP: + manager->do_rtcp = g_value_get_boolean (value); + break; + case PROP_LATENCY: + manager->latency = g_value_get_uint (value); + break; + case PROP_UDP_BUFFER_SIZE: + manager->udp_buffer_size = g_value_get_int (value); + break; + case PROP_UDP_TIMEOUT: + manager->udp_timeout = g_value_get_uint64 (value); + break; + case PROP_ENABLE_PAD_PROBE: + manager->enable_pad_probe = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void wfd_rtsp_manager_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + WFDRTSPManager *manager; + + manager = WFD_RTSP_MANAGER_CAST (object); + + switch (prop_id) { + case PROP_DO_RTCP: + g_value_set_boolean (value, manager->do_rtcp); + break; + case PROP_LATENCY: + g_value_set_uint (value, manager->latency); + break; + case PROP_UDP_BUFFER_SIZE: + g_value_set_int (value, manager->udp_buffer_size); + break; + case PROP_UDP_TIMEOUT: + g_value_set_uint64 (value, manager->udp_timeout); + break; + case PROP_ENABLE_PAD_PROBE: + g_value_set_boolean (value, manager->enable_pad_probe); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +pad_unblocked (GstPad * pad, gboolean blocked, WFDRTSPManager *manager) +{ + GST_DEBUG_OBJECT (manager, "pad %s:%s unblocked", GST_DEBUG_PAD_NAME (pad)); +} + + +static gboolean +wfd_rtsp_manager_activate (WFDRTSPManager *manager) +{ + GST_DEBUG_OBJECT (manager, "activating streams"); + + if (manager->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 (manager->udpsrc[0]), "timeout", (guint64) 0, NULL); + } + + if (manager->srcpad) { + GST_DEBUG_OBJECT (manager, "setting pad caps for manager %p", manager); + gst_pad_set_caps (manager->srcpad, manager->caps); + + GST_DEBUG_OBJECT (manager, "activating manager pad %p", manager); + gst_pad_set_active (manager->srcpad, TRUE); + } + + /* unblock all pads */ + if (manager->blockedpad && manager->blockid != 0) { + GST_DEBUG_OBJECT (manager, "unblocking manager pad %p", manager); + gst_pad_remove_probe (manager->blockedpad, manager->blockid); + manager->blockid = 0; + manager->blockedpad = NULL; + } + + return TRUE; +} + + +static void +pad_blocked (GstPad * pad, gboolean blocked, WFDRTSPManager *manager) +{ + GST_DEBUG_OBJECT (manager, "pad %s:%s blocked, activating streams", + GST_DEBUG_PAD_NAME (pad)); + + /* activate the streams */ +// GST_OBJECT_LOCK (manager); + if (!manager->need_activate) + goto was_ok; + + manager->need_activate = FALSE; +// GST_OBJECT_UNLOCK (manager); + + wfd_rtsp_manager_activate (manager); + + return; + +was_ok: + { +// GST_OBJECT_UNLOCK (manager); + return; + } +} + + +static gboolean +wfd_rtsp_manager_configure_udp (WFDRTSPManager *manager, gint rtpport, gint rtcpport) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + GstElement *udpsrc0 = NULL, *udpsrc1 = NULL; + gint tmp_rtp = 0, tmp_rtcp = 0; + const gchar *host; + GstCaps *caps; + GstPad *outpad = NULL; + + if (manager->is_ipv6) + host = "udp://[::0]"; + else + host = "udp://0.0.0.0"; + + 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", rtpport, "reuse", FALSE, NULL); + + if (manager->udp_buffer_size != 0) { + g_object_set (G_OBJECT (udpsrc0), "buffer-size", manager->udp_buffer_size, + NULL); + g_object_set (G_OBJECT (udpsrc0), "blocksize", manager->udp_buffer_size, + NULL); + } + + caps = gst_caps_new_simple ("application/x-rtp", + "media", G_TYPE_STRING, "video", "payload", G_TYPE_INT, 33, + "clock-rate", G_TYPE_INT, 90000, "encoding-params", G_TYPE_STRING, "MP2T-ES", NULL); + + g_object_set (udpsrc0, "caps", caps, NULL); + gst_caps_unref (caps); + + ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED); + if (ret == GST_STATE_CHANGE_FAILURE) { + GST_DEBUG_OBJECT (manager, "fail to change state udpsrc for RTP"); + goto no_udp_protocol; + } + + g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL); + GST_DEBUG_OBJECT (manager, "got RTP port %d", tmp_rtp); + + /* check if port is even */ + if ((tmp_rtp & 0x01) != 0) { + GST_DEBUG_OBJECT (rtpport, "RTP port not even"); + goto no_ports; + } + + /* 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; + + g_object_set (G_OBJECT (udpsrc1), "port", rtcpport, "reuse", FALSE, NULL); + + GST_DEBUG_OBJECT (manager, "starting RTCP on port %d", rtcpport); + ret = gst_element_set_state (udpsrc1, GST_STATE_PAUSED); + if (ret == GST_STATE_CHANGE_FAILURE) { + GST_DEBUG_OBJECT (manager, "fail to change state udpsrc for RTCP"); + goto no_udp_rtcp_protocol; + } + + /* all fine, do port check */ + g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL); + g_object_get (G_OBJECT (udpsrc1), "port", &tmp_rtcp, 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. */ + manager->udpsrc[0] = gst_object_ref (udpsrc0); + manager->udpsrc[1] = gst_object_ref (udpsrc1); + + /* they are ours now */ + gst_object_ref_sink (udpsrc0); + gst_object_ref_sink (udpsrc1); + + if (manager->udpsrc[0]) { + gst_bin_add (GST_BIN_CAST (manager->wfdrtspsrc), manager->udpsrc[0]); + + GST_DEBUG_OBJECT (manager, "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 (manager->udpsrc[0]), "timeout", manager->udp_timeout, + NULL); + + GST_DEBUG_OBJECT (manager, "got outpad from udpsrc"); + /* get output pad of the UDP source. */ + outpad = gst_element_get_static_pad (manager->udpsrc[0], "src"); + + /* save it so we can unblock */ + manager->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. */ + manager->blockid = gst_pad_add_probe(manager->blockedpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, + (GstPadProbeCallback) pad_blocked, manager, NULL); + + /* RTP port */ + if (manager->channelpad[0]) { + GST_DEBUG_OBJECT (manager, "connecting to session"); + /* configure for UDP delivery, we need to connect the UDP pads to + * the session plugin. */ + gst_pad_link (outpad, manager->channelpad[0]); + gst_object_unref (outpad); + outpad = NULL; + /* we connected to pad-added signal to get pads from the manager */ + } else { + GST_DEBUG_OBJECT (manager, "using UDP src pad as output"); + } + } + + /* RTCP port */ + if (manager->udpsrc[1]) { + gst_bin_add (GST_BIN_CAST (manager->wfdrtspsrc), manager->udpsrc[1]); + + if (manager->channelpad[1]) { + GstPad *pad; + + GST_DEBUG_OBJECT (manager, "connecting UDP source 1 to manager"); + + pad = gst_element_get_static_pad (manager->udpsrc[1], "src"); + gst_pad_link (pad, manager->channelpad[1]); + gst_object_unref (pad); + } else { + /* leave unlinked */ + } + } + + return TRUE; + + /* ERRORS */ +no_udp_protocol: + { + GST_DEBUG_OBJECT (manager, "could not get UDP source"); + goto cleanup; + } +no_ports: + { + GST_DEBUG_OBJECT (manager, "could not allocate UDP port pair"); + goto cleanup; + } +no_udp_rtcp_protocol: + { + GST_DEBUG_OBJECT (manager, "could not get UDP source for RTCP"); + goto cleanup; + } +port_error: + { + GST_DEBUG_OBJECT (manager, "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_wfdrtspsrc_get_transport_info (WFDRTSPManager * manager, + GstRTSPTransport * transport, const gchar ** destination, gint * min, gint * max) +{ + g_return_if_fail (transport); + g_return_if_fail (transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP); + + if (destination) { + /* first take the source, then the endpoint to figure out where to send + * the RTCP. */ + if (!(*destination = transport->source)) { + if (manager->control_connection ) + *destination = gst_rtsp_connection_get_ip (manager->control_connection ); + else if (manager->conninfo.connection) + *destination = + gst_rtsp_connection_get_ip (manager->conninfo.connection); + } + } + if (min && max) { + /* for unicast we only expect the ports here */ + *min = transport->server_port.min; + *max = transport->server_port.max; + } +} + + +/* configure the UDP sink back to the server for status reports */ +static gboolean +wfd_rtsp_manager_configure_udp_sinks ( WFDRTSPManager * manager, GstRTSPTransport * transport) +{ + GstPad *pad = NULL; + gint rtp_port = -1, rtcp_port = -1, sockfd = -1; + gboolean do_rtp = FALSE, do_rtcp = FALSE; + const gchar *destination = NULL; + gchar *uri = NULL; + + /* get transport info */ + gst_wfdrtspsrc_get_transport_info (manager, transport, &destination, + &rtp_port, &rtcp_port); + + /* 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 && manager->session != NULL && manager->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 (manager, "configure RTP UDP sink for %s:%d", destination, + rtp_port); + + uri = g_strdup_printf ("udp://%s:%d", destination, rtp_port); + manager->udpsink[0] = gst_element_make_from_uri (GST_URI_SINK, uri, NULL, NULL); + g_free (uri); + if (manager->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 (manager->udpsink[0]), "auto-multicast", FALSE, + "loop", FALSE, "sync", FALSE, "async", FALSE, NULL); + + if (manager->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 (manager->udpsrc[0]), "socket", &sockfd, NULL); + GST_DEBUG_OBJECT (manager, "RTP UDP src has sock %d", sockfd); + /* configure socket and make sure udpsink does not close it when shutting + * down, it belongs to udpsrc after all. */ + g_object_set (G_OBJECT (manager->udpsink[0]), "socket", sockfd, + "close-socket", FALSE, NULL); + } + + /* the source for the dummy packets to open up NAT */ + manager->fakesrc = gst_element_factory_make ("fakesrc", NULL); + if (manager->fakesrc == NULL) + goto no_fakesrc_element; + + /* random data in 5 buffers, a size of 200 bytes should be fine */ + g_object_set (G_OBJECT (manager->fakesrc), "filltype", 3, "num-buffers", 5, + "sizetype", 2, "sizemax", 200, "silent", TRUE, NULL); + + /* we don't want to consider this a sink */ + GST_OBJECT_FLAG_UNSET (manager->udpsink[0], GST_ELEMENT_FLAG_SINK); + + /* keep everything locked */ + gst_element_set_locked_state (manager->udpsink[0], TRUE); + gst_element_set_locked_state (manager->fakesrc, TRUE); + + gst_object_ref (manager->udpsink[0]); + gst_bin_add (GST_BIN_CAST (manager->wfdrtspsrc), manager->udpsink[0]); + gst_object_ref (manager->fakesrc); + gst_bin_add (GST_BIN_CAST (manager->wfdrtspsrc), manager->fakesrc); + + gst_element_link (manager->fakesrc, manager->udpsink[0]); + } + if (do_rtcp) { + GST_DEBUG_OBJECT (manager, "configure RTCP UDP sink for %s:%d", destination, + rtcp_port); + + uri = g_strdup_printf ("udp://%s:%d", destination, rtcp_port); + manager->udpsink[1] = gst_element_make_from_uri (GST_URI_SINK, uri, NULL, NULL); + g_free (uri); + if (manager->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 (manager->udpsink[1]), "auto-multicast", FALSE, + "loop", FALSE, "sync", FALSE, "async", FALSE, NULL); + + if (manager->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 (manager->udpsrc[1]), "socket", &sockfd, NULL); + GST_DEBUG_OBJECT (manager, "RTCP UDP src has sock %d", sockfd); + /* configure socket and make sure udpsink does not close it when shutting + * down, it belongs to udpsrc after all. */ + g_object_set (G_OBJECT (manager->udpsink[1]), "socket", sockfd, + "close-socket", FALSE, NULL); + } + + /* we don't want to consider this a sink */ + GST_OBJECT_FLAG_UNSET (manager->udpsink[1], GST_ELEMENT_FLAG_SINK); + + /* we keep this playing always */ + gst_element_set_locked_state (manager->udpsink[1], TRUE); + gst_element_set_state (manager->udpsink[1], GST_STATE_PLAYING); + + gst_object_ref (manager->udpsink[1]); + gst_bin_add (GST_BIN_CAST (manager->wfdrtspsrc), manager->udpsink[1]); + + manager->rtcppad = gst_element_get_static_pad (manager->udpsink[1], "sink"); + + /* get session RTCP pad */ + pad = gst_element_get_request_pad (manager->session, "send_rtcp_src"); + + /* and link */ + if (pad) { + gst_pad_link (pad, manager->rtcppad); + gst_object_unref (pad); + } + } + + return TRUE; + + /* ERRORS */ +no_destination: + { + GST_DEBUG_OBJECT (manager, "no destination address specified"); + return FALSE; + } +no_sink_element: + { + GST_DEBUG_OBJECT (manager, "no UDP sink element found"); + return FALSE; + } +no_fakesrc_element: + { + GST_DEBUG_OBJECT (manager, "no fakesrc element found"); + return FALSE; + } +} + +static void +on_bye_ssrc (GObject * session, GObject * source, WFDRTSPManager * manager) +{ + GST_DEBUG_OBJECT (manager, "source in session received BYE"); + + //gst_wfdrtspsrc_do_stream_eos (src, manager); +} + +static void +on_new_ssrc (GObject * session, GObject * source, WFDRTSPManager * manager) +{ + GST_DEBUG_OBJECT (manager, "source in session received NEW"); +} + +static void +on_timeout (GObject * session, GObject * source, WFDRTSPManager * manager) +{ + GST_DEBUG_OBJECT (manager, "source in session timed out"); + + //gst_wfdrtspsrc_do_stream_eos (src, manager); +} + +static void +on_ssrc_active (GObject * session, GObject * source, WFDRTSPManager * manager) +{ + GST_DEBUG_OBJECT (manager, "source in session is active"); +} + + +static GstCaps * +request_pt_map_for_jitterbuffer (GstElement * jitterbuffer, guint pt, WFDRTSPManager * manager) +{ + GstCaps *caps; + + if (!manager) + goto unknown_stream; + + GST_DEBUG_OBJECT (manager, "getting pt map for pt %d", pt); + + WFD_RTSP_MANAGER_STATE_LOCK (manager); + + caps = manager->caps; + if (caps) + gst_caps_ref (caps); + WFD_RTSP_MANAGER_STATE_UNLOCK (manager); + + return caps; + +unknown_stream: + { + GST_ERROR ( " manager is NULL"); + return NULL; + } +} + +static GstCaps * +request_pt_map_for_session (GstElement * session, guint session_id, guint pt, WFDRTSPManager * manager) +{ + GstCaps *caps; + + GST_DEBUG_OBJECT (manager, "getting pt map for pt %d in session %d", pt, session_id); + + WFD_RTSP_MANAGER_STATE_LOCK (manager); + caps = manager->caps; + if (caps) + gst_caps_ref (caps); + WFD_RTSP_MANAGER_STATE_UNLOCK (manager); + + return caps; +} + + +static void +wfd_rtsp_manager_do_stream_eos (WFDRTSPManager * manager) +{ + GST_DEBUG_OBJECT (manager, "setting for session to EOS"); + + if (manager->eos) + goto was_eos; + + manager->eos = TRUE; + //gst_wfdrtspsrc_stream_push_event (src, manager, gst_event_new_eos (), TRUE); + return; + + /* ERRORS */ +was_eos: + { + GST_DEBUG_OBJECT (manager, "already EOS"); + return; + } +} + +static gboolean +wfd_rtsp_manager_set_manager (WFDRTSPManager * manager) +{ + g_return_val_if_fail (manager, FALSE); + + if (manager->session) { + g_signal_connect (manager->session, "on-bye-ssrc", (GCallback) on_bye_ssrc, + manager); + g_signal_connect (manager->session, "on-bye-timeout", (GCallback) on_timeout, + manager); + g_signal_connect (manager->session, "on-timeout", (GCallback) on_timeout, + manager); + g_signal_connect (manager->session, "on-ssrc-active", + (GCallback) on_ssrc_active, manager); + g_signal_connect (manager->session, "on-new-ssrc", (GCallback) on_new_ssrc, + manager); + g_signal_connect (manager->session, "request-pt-map", + (GCallback) request_pt_map_for_session, manager); + + g_object_set (G_OBJECT(manager->session), "rtcp-min-interval", (guint64)1000000000, NULL); + } + + if (manager->jitterbuffer != NULL) { + /* configure latency and packet lost */ + g_object_set (manager->jitterbuffer, "latency", manager->latency, NULL); + + g_signal_connect (manager->jitterbuffer, "request-pt-map", + (GCallback) request_pt_map_for_jitterbuffer, manager); + } + + return TRUE; +} + + +gboolean +wfd_rtsp_manager_configure_transport (WFDRTSPManager * manager, + GstRTSPTransport * transport, gint rtpport, gint rtcpport) +{ + GstStructure *s; + const gchar *mime; + + GST_DEBUG_OBJECT (manager, "configuring transport"); + + s = gst_caps_get_structure (manager->caps, 0); + + /* get the proper mime type for this manager now */ + if (gst_rtsp_transport_get_mime (transport->trans, &mime) < 0) + goto unknown_transport; + if (!mime) + goto unknown_transport; + + /* configure the final mime type */ + GST_DEBUG_OBJECT (manager, "setting mime to %s", mime); + gst_structure_set_name (s, mime); + + if (!wfd_rtsp_manager_set_manager (manager)) + goto no_manager; + + switch (transport->lower_transport) { + case GST_RTSP_LOWER_TRANS_TCP: + case GST_RTSP_LOWER_TRANS_UDP_MCAST: + goto transport_failed; + case GST_RTSP_LOWER_TRANS_UDP: + if (!wfd_rtsp_manager_configure_udp (manager, rtpport, rtcpport)) + goto transport_failed; + if (!wfd_rtsp_manager_configure_udp_sinks (manager, transport)) + goto transport_failed; + break; + default: + goto unknown_transport; + } + + manager->need_activate = TRUE; + manager->protocol = transport->lower_transport; + + return TRUE; + + /* ERRORS */ +transport_failed: + { + GST_DEBUG_OBJECT (manager, "failed to configure transport"); + return FALSE; + } +unknown_transport: + { + GST_DEBUG_OBJECT (manager, "unknown transport"); + return FALSE; + } +no_manager: + { + GST_DEBUG_OBJECT (manager, "cannot get a session manager"); + return FALSE; + } +} + +GstPadProbeReturn +//wfd_rtsp_manager_pad_probe_cb(GstPad * pad, GstMiniObject * object, gpointer u_data) +wfd_rtsp_manager_pad_probe_cb(GstPad * pad, GstPadProbeInfo *info, gpointer u_data) +{ + GstElement* parent = NULL; + const GstSegment *segment = NULL; + + parent = (GstElement*)gst_object_get_parent(GST_OBJECT(pad)); + +#if 0 + if (GST_IS_EVENT (object)) { + GstEvent *event = GST_EVENT_CAST(object); + + /* show name and event type */ + GST_DEBUG_OBJECT(WFD_RTSP_MANAGER (u_data), "EVENT PROBE : %s:%s : %s\n", + GST_STR_NULL(GST_ELEMENT_NAME(parent)), GST_STR_NULL(GST_PAD_NAME(pad)), + GST_EVENT_TYPE_NAME(event)); + + if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) { + GstSegment *seg = NULL; + + gst_event_parse_segment (event, &segment); + + GST_DEBUG_OBJECT (WFD_RTSP_MANAGER (u_data), "NEWSEGMENT : %" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT " \n", + seg->start, seg->stop, seg->time); + gst_segment_free(seg); + } + } + else if (GST_IS_BUFFER(object)) { + GstBuffer *buffer = GST_BUFFER_CAST(object); + + /* show name and timestamp */ + GST_DEBUG_OBJECT(WFD_RTSP_MANAGER (u_data), "BUFFER PROBE : %s:%s : %u:%02u:%02u.%09u (%d bytes)\n", + GST_STR_NULL(GST_ELEMENT_NAME(parent)), GST_STR_NULL(GST_PAD_NAME(pad)), + GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)), gst_buffer_get_size(buffer)); + } +#else + if (info->type == GST_PAD_PROBE_TYPE_BUFFER) { + GstBuffer *buffer = gst_pad_probe_info_get_buffer (info); + + /* show name and timestamp */ + GST_DEBUG_OBJECT(WFD_RTSP_MANAGER (u_data), "BUFFER PROBE : %s:%s : %u:%02u:%02u.%09u (%d bytes)\n", + GST_STR_NULL(GST_ELEMENT_NAME(parent)), GST_STR_NULL(GST_PAD_NAME(pad)), + GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)), gst_buffer_get_size(buffer)); + } else if (info->type == GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM || + info->type == GST_PAD_PROBE_TYPE_EVENT_UPSTREAM || + info->type == GST_PAD_PROBE_TYPE_EVENT_FLUSH || + info->type == GST_PAD_PROBE_TYPE_EVENT_BOTH) { + GstEvent *event = gst_pad_probe_info_get_event (info); + /* show name and event type */ + GST_DEBUG_OBJECT(WFD_RTSP_MANAGER (u_data), "EVENT PROBE : %s:%s : %s\n", + GST_STR_NULL(GST_ELEMENT_NAME(parent)), GST_STR_NULL(GST_PAD_NAME(pad)), + GST_EVENT_TYPE_NAME(event)); + + if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) { + GstSegment *seg = NULL; + + gst_event_parse_segment (event, &segment); + + GST_DEBUG_OBJECT (WFD_RTSP_MANAGER (u_data), "NEWSEGMENT : %" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT " \n", + seg->start, seg->stop, seg->time); + gst_segment_free(seg); + } + } + + + +#endif + + if ( parent ) { + gst_object_unref(parent); + } + + return GST_PAD_PROBE_OK; +} + +void wfd_rtsp_manager_enable_pad_probe(WFDRTSPManager * manager) +{ + GstPad * pad = NULL; + + g_return_if_fail(manager); + + if(manager->udpsrc[0]) { + pad = NULL; + pad = gst_element_get_static_pad(manager->udpsrc[0], "src"); + if (pad) { + if( gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM, wfd_rtsp_manager_pad_probe_cb, (gpointer)manager, NULL)) { + GST_DEBUG_OBJECT (manager, "added pad probe (pad : %s, element : %s)", gst_pad_get_name(pad), gst_element_get_name(manager->udpsrc[0])); + } + gst_object_unref (pad); + pad = NULL; + } + } + + if(manager->session) { + pad = gst_element_get_static_pad(manager->session, "recv_rtp_src"); + if (pad) { + if( gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM, wfd_rtsp_manager_pad_probe_cb, (gpointer)manager, NULL)) { + GST_DEBUG_OBJECT (manager, "added pad probe (pad : %s, element : %s)", gst_pad_get_name(pad), gst_element_get_name(manager->session)); + } + gst_object_unref (pad); + pad = NULL; + } + } +#if 0 + if(manager->requester) { + pad = gst_element_get_static_pad(manager->requester, "rtp_sink"); + if (pad) { + if( gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM, wfd_rtsp_manager_pad_probe_cb, (gpointer)manager, NULL)) { + GST_DEBUG_OBJECT (manager, "added pad probe (pad : %s, element : %s)", gst_pad_get_name(pad), gst_element_get_name(manager->requester)); + } + gst_object_unref (pad); + pad = NULL; + } + + pad = gst_element_get_static_pad(manager->requester, "rtp_src"); + if (pad) { + if( gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM, wfd_rtsp_manager_pad_probe_cb, (gpointer)manager, NULL)) { + GST_DEBUG_OBJECT (manager, "added pad probe (pad : %s, element : %s)", gst_pad_get_name(pad), gst_element_get_name(manager->requester)); + } + gst_object_unref (pad); + pad = NULL; + } + } +#endif + + if(manager->jitterbuffer) { + pad = gst_element_get_static_pad(manager->jitterbuffer, "sink"); + if (pad) { + if( gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM, wfd_rtsp_manager_pad_probe_cb, (gpointer)manager, NULL)) { + GST_DEBUG_OBJECT (manager, "added pad probe (pad : %s, element : %s)", gst_pad_get_name(pad), gst_element_get_name(manager->jitterbuffer)); + } + gst_object_unref (pad); + pad = NULL; + } + } + +} + diff --git a/wfdrtspsrc/src/wfdrtspmanager.h b/wfdrtspsrc/src/wfdrtspmanager.h new file mode 100755 index 0000000..227517f --- /dev/null +++ b/wfdrtspsrc/src/wfdrtspmanager.h @@ -0,0 +1,159 @@ +/* + * wfdrtspmanager + * + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: JongHyuk Choi + * + * 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. + */ + +#ifndef __GST_WFD_RTSP_MANAGER_H__ +#define __GST_WFD_RTSP_MANAGER_H__ + +#include +#include +#include +#include + + +G_BEGIN_DECLS + + +typedef struct _WFDRTSPManager WFDRTSPManager; +typedef struct _WFDRTSPManagerClass WFDRTSPManagerClass; + +#define WFD_TYPE_RTSP_MANAGER (wfd_rtsp_manager_get_type()) +#define WFD_RTSP_MANAGER(ext) (G_TYPE_CHECK_INSTANCE_CAST((ext),WFD_TYPE_RTSP_MANAGER, WFDRTSPManager)) +#define WFD_RTSP_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),WFD_TYPE_RTSP_MANAGER,WFDRTSPManagerClass)) +#define WFD_IS_RTSP_MANAGER(ext) (G_TYPE_CHECK_INSTANCE_TYPE((ext),WFD_TYPE_RTSP_MANAGER)) +#define WFD_IS_RTSP_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),WFD_TYPE_RTSP_MANAGER)) +#define WFD_RTSP_MANAGER_CAST(ext) ((WFDRTSPManager *)(ext)) + + +#define WFD_RTSP_MANAGER_STATE_GET_LOCK(manager) (WFD_RTSP_MANAGER_CAST(manager)->state_rec_lock) +#define WFD_RTSP_MANAGER_STATE_LOCK(manager) (g_static_rec_mutex_lock (WFD_RTSP_MANAGER_STATE_GET_LOCK(manager))) +#define WFD_RTSP_MANAGER_STATE_UNLOCK(manager) (g_static_rec_mutex_unlock (WFD_RTSP_MANAGER_STATE_GET_LOCK(manager))) + +typedef struct _GstWFDRTSPConnInfo GstWFDRTSPConnInfo; + +struct _GstWFDRTSPConnInfo { + gchar *location; + GstRTSPUrl *url; + gchar *url_str; + GstRTSPConnection *connection; + gboolean connected; +}; + +struct _WFDRTSPManager { + GObject object; + + GstElement *wfdrtspsrc; /* parent, no extra ref to parent is taken */ + + /* pad we expose or NULL when it does not have an actual pad */ + GstPad *srcpad; + gboolean eos; + gboolean discont; + gboolean need_activate; + GStaticRecMutex *state_rec_lock; + + /* for interleaved mode */ + GstCaps *caps; + 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; + + /* original control url */ + gchar *control_url; + GstRTSPConnection *control_connection; + + guint64 seqbase; + guint64 timebase; + + /* per manager connection */ + GstWFDRTSPConnInfo conninfo; + + /* pipeline */ + GstElement *requester; + GstElement *session; + GstElement *jitterbuffer; + + /* properties */ + gboolean do_rtcp; + guint latency; + gint udp_buffer_size; + guint64 udp_timeout; + gboolean enable_pad_probe; + + GstRTSPLowerTrans protocol; +}; + +struct _WFDRTSPManagerClass { + GObjectClass parent_class; +}; + +GType wfd_rtsp_manager_get_type (void); + + +WFDRTSPManager* +wfd_rtsp_manager_new (GstElement *wfdrtspsrc); + +gboolean +wfd_rtsp_manager_configure_transport (WFDRTSPManager * manager, + GstRTSPTransport * transport, gint rtpport, gint rtcpport); + +GstRTSPResult +wfd_rtsp_manager_message_dump (GstRTSPMessage * msg); +void +wfd_rtsp_manager_enable_pad_probe(WFDRTSPManager * manager); + +G_END_DECLS + +#endif /* __GST_WFD_RTSP_MANAGER_H__ */ diff --git a/xvimagesrc/Makefile.am b/xvimagesrc/Makefile.am new file mode 100644 index 0000000..af437a6 --- /dev/null +++ b/xvimagesrc/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/xvimagesrc/src/Makefile.am b/xvimagesrc/src/Makefile.am new file mode 100644 index 0000000..d37cedb --- /dev/null +++ b/xvimagesrc/src/Makefile.am @@ -0,0 +1,26 @@ +# plugindir is set in configure + +############################################################################## +# change libgstplugin.la to something more suitable, e.g. libmysomething.la # +############################################################################## +plugin_LTLIBRARIES = libgstxvimagesrc.la + +############################################################################## +# for the next set of variables, rename the prefix if you renamed the .la, # +# e.g. libgstplugin_la_SOURCES => libmysomething_la_SOURCES # +# libgstplugin_la_CFLAGS => libmysomething_la_CFLAGS # +# libgstplugin_la_LIBADD => libmysomething_la_LIBADD # +# libgstplugin_la_LDFLAGS => libmysomething_la_LDFLAGS # +############################################################################## + +# sources used to compile this plug-in +libgstxvimagesrc_la_SOURCES = gstxvimagesrc.c + +# flags used to compile this plugin +# add other _CFLAGS and _LIBS as needed +libgstxvimagesrc_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(TBM_CFLAGS) $(DRI2_CFLAGS) $(X11_CFLAGS) $(XEXT_CFLAGS) $(XV_CFLAGS) $(XDAMAGE_CFLAGS) $(DRM_DEVEL_CFLAGS) $(DRM_CFLAGS) +libgstxvimagesrc_la_LIBADD = $(GST_LIBS) $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(TBM_LIBS)$(DRI2_LIBS) $(X11_LIBS) $(XEXT_LIBS) $(XV_LIBS) $(XDAMAGE_LIBS) $(DRM_LIBS) $(DRM_DEVEL_LIBS) +libgstxvimagesrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +# headers we need but don't want installed +noinst_HEADERS = gstxvimagesrc.h diff --git a/xvimagesrc/src/gstxvimagesrc.c b/xvimagesrc/src/gstxvimagesrc.c new file mode 100644 index 0000000..fcc2d04 --- /dev/null +++ b/xvimagesrc/src/gstxvimagesrc.c @@ -0,0 +1,1875 @@ +/* + * xvimagesrc + * + * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyunjun Ko + * + * 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-xvimagesrc +* +* xvimagesrc captures frame buffer which includes the application data along with video layer data +* from the XServer and pushes the data to the downstream element. +* +* +* +* Example launch line +* |[ +* gst-launch xvimagesrc ! "video/x-raw, width=720, height=1280, framerate=(fraction)30/1, format=(string)ST12" ! fakesink +* ]| captures the frame buffer from the XServer and send the buffers to a fakesink. +* +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstxvimagesrc.h" + +/* headers for drm */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GST_DEBUG_CATEGORY_STATIC (xvimagesrc_debug); +#define GST_CAT_DEFAULT xvimagesrc_debug + +#define GST_XV_IMAGE_SRC_CAPS \ + "video/x-raw, " \ + "format = (string) RGBx, " \ + "width = (int) [ 16, 4096 ], " \ + "height = (int) [ 16, 4096 ], " \ + "framerate = (fraction) [0/1, 2147483647/1];" \ + "video/x-raw," \ + "format = (string) { SN12, ST12 }, " \ + "width = (int) [ 1, 4096 ], " \ + "height = (int) [ 1, 4096 ], " \ + "framerate = (fraction) [0/1, 2147483647/1];" + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_XV_IMAGE_SRC_CAPS) + ); + +enum +{ + PROP_0 +}; + +enum +{ + VIDEO_TYPE_VIDEO_WITH_UI, + VIDEO_TYPE_VIDEO_ONLY, +}; + +enum +{ + SIGNAL_VIDEO_WITH_UI = 0, + SIGNAL_VIDEO_ONLY, + SIGNAL_SELECTION_NOTIFY, + SIGNAL_LAST +}; + +#define GEM_NAME_MAX 10 + +#define SCMN_CS_YUV420 1 /* Y:U:V 4:2:0 */ +#define SCMN_CS_I420 SCMN_CS_YUV420 /* Y:U:V */ +#define SCMN_CS_NV12 6 +#define SCMN_CS_NV12_T64X32 11 /* 64x32 Tiled NV12 type */ +#define SCMN_CS_UYVY 100 +#define SCMN_CS_YUYV 101 +#define SCMN_CS_YUY2 SCMN_CS_YUYV + +typedef struct +{ + void *address[GEM_NAME_MAX]; + int buffer_size[GEM_NAME_MAX]; + int name[GEM_NAME_MAX]; + gint32 fd[GEM_NAME_MAX]; + gint32 handle[GEM_NAME_MAX]; +} GEM_MMAP; + +typedef enum +{ + BUF_SHARE_METHOD_PADDR = 0, + BUF_SHARE_METHOD_FD, + BUF_SHARE_METHOD_TIZEN_BUFFER +} buf_share_method_t; + +typedef struct GstXvImageOutBuffer GstXvImageOutBuffer; + +struct GstXvImageOutBuffer +{ + GstBuffer *buffer; + int fd_name; + unsigned int YBuf; + tbm_bo bo[2]; + GstXVImageSrc *xvimagesrc; +}; + +static guint gst_xv_image_src_signals[SIGNAL_LAST] = { 0 }; + +static const char fake_edid_info[] = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78, + 0x0a, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0xbd, + 0xee, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x66, 0x21, 0x50, 0xb0, 0x51, 0x00, + 0x1b, 0x30, 0x40, 0x70, 0x36, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, + 0x01, 0x1d, 0x00, 0x72, 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00, + 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, + 0x4b, 0x1a, 0x44, 0x17, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0xfc, 0x00, 0x53, 0x41, 0x4d, 0x53, 0x55, 0x4e, 0x47, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xbc, 0x02, 0x03, 0x1e, 0xf1, + 0x46, 0x84, 0x05, 0x03, 0x10, 0x20, 0x22, 0x23, 0x09, 0x07, 0x07, 0x83, + 0x01, 0x00, 0x00, 0xe2, 0x00, 0x0f, 0x67, 0x03, 0x0c, 0x00, 0x10, 0x00, + 0xb8, 0x2d, 0x01, 0x1d, 0x80, 0x18, 0x71, 0x1c, 0x16, 0x20, 0x58, 0x2c, + 0x25, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x9e, 0x8c, 0x0a, 0xd0, 0x8a, + 0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xa0, 0x5a, 0x00, 0x00, + 0x00, 0x18, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c, + 0x45, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 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, 0x06 +}; + +//#define _MAKE_DUMP +#ifdef _MAKE_DUMP +#define YUV_FRAME_SIZE 3110400 +#define YUV_720_FRAME_SIZE 1382400 +#define YUV_VGA_FRAME_SIZE 460800 + +static int g_prev_frame[YUV_FRAME_SIZE] = { 0, }; + +static unsigned char g_dump_frame[100][921600]; +static unsigned char g_dump_frame1[100][462848]; +//static int g_dump_frame[100][YUV_720_FRAME_SIZE]; +//static int g_dump_frame[200][YUV_VGA_FRAME_SIZE]; +static int f_idx = 0; +static int f_done = 0; +#endif + +//#define COUNT_FRAMES +#define BASE_TIME 33000 +#define LIMIT_TIME -33000 + +#ifdef COUNT_FRAMES +gchar old_time[10] = { 0, }; +#endif + +static gboolean error_caught = FALSE; + +#define BUFFER_COND_WAIT_TIMEOUT 1000000 +//#define GST_TYPE_GST_XV_IMAGE_OUT_BUFFER (gst_xv_image_out_buffer_get_type()) +//#define GST_IS_GST_XV_IMAGE_OUT_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_GST_XV_IMAGE_OUT_BUFFER)) +//static void gst_xv_image_out_buffer_finalize (GstXvImageOutBuffer * buffer); +static GstXvImageOutBuffer *gst_xv_image_out_buffer_new (GstXVImageSrc * src); + +static void gst_xv_image_src_finalize (GObject * gobject); + +static void gst_xv_image_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_xv_image_src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static GstFlowReturn gst_xv_image_src_create (GstPushSrc * psrc, + GstBuffer ** outbuf); +static GstStateChangeReturn gst_xv_image_src_change_state (GstElement * element, + GstStateChange transition); +static gboolean gst_xv_image_src_start (GstBaseSrc * bsrc); +static gboolean gst_xv_image_src_stop (GstBaseSrc * bsrc); +static gboolean gst_xv_image_src_get_size (GstBaseSrc * bsrc, guint64 * size); +static gboolean gst_xv_image_src_is_seekable (GstBaseSrc * bsrc); +static gboolean gst_xv_image_src_query (GstBaseSrc * bsrc, GstQuery * query); +static gboolean gst_xv_image_src_unlock (GstBaseSrc * bsrc); +static gboolean gst_xv_image_src_unlock_stop (GstBaseSrc * bsrc); +static gboolean gst_xv_image_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps); + +static tbm_bufmgr bufmgr_get (Display * dpy, Pixmap pixmap); +static int port_get (GstXVImageSrc * src, unsigned int id); +static void pixmap_update (GstXVImageSrc * src, Display * dpy, + tbm_bufmgr bufmgr, Pixmap pixmap, int x, int y, int width, int height); +static Pixmap pixmap_create (GstXVImageSrc * src, Display * dpy, int width, + int height); + +static void *gst_xv_image_src_update_thread (void *asrc); +static gboolean xvimagesrc_thread_start (GstXVImageSrc * src); +static void drm_init (GstXVImageSrc * src); +static void drm_finalize (GstXVImageSrc * src); +static tbm_bo drm_convert_gem_to_bo (tbm_bufmgr bufmgr, unsigned int gem_name); +static gint32 drm_convert_gem_to_fd (int *gemname_cnt, int drm_fd, + unsigned int name, void *data, void **virtual_address, guint * buf_size); +static void gst_xv_get_image_sleep (void *asrc, long duration); + +static void +_do_init (GType type) +{ + GST_DEBUG_CATEGORY_INIT (xvimagesrc_debug, "xvimagesrc", 0, "Xv image src"); +} + +#define gst_xv_image_src_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstXVImageSrc, gst_xv_image_src, GST_TYPE_PUSH_SRC, + _do_init (G_TYPE_INVALID)); + +//G_DEFINE_BOXED_TYPE (GstXvImageOutBuffer, gst_xv_image_out_buffer, NULL, +// gst_xv_image_out_buffer_finalize); + +#ifdef DEBUG_BUFFER +int value[5] = { 0 }; + +static int value_count = 0; +#endif + + +static GstXvImageOutBuffer * +gst_xv_image_out_buffer_new (GstXVImageSrc * src) +{ + GstXvImageOutBuffer *newbuf = NULL; + GST_LOG ("gst_omx_out_buffer_new"); + + newbuf = (GstXvImageOutBuffer *) malloc (sizeof (GstXvImageOutBuffer)); + if (!newbuf) { + GST_ERROR ("gst_omx_out_buffer_new out of memory"); + return NULL; + } + GST_LOG ("creating buffer : %p", newbuf); + newbuf->buffer = gst_buffer_new (); + newbuf->xvimagesrc = gst_object_ref (GST_OBJECT (src)); + newbuf->fd_name = 0; + newbuf->YBuf = 0; + newbuf->bo[0] = NULL; + newbuf->bo[1] = NULL; + return newbuf; +} + +static void +gst_xv_image_src_class_init (GstXVImageSrcClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSrcClass *gstbasesrc_class; + GstPushSrcClass *gstpushsrc_class; + gobject_class = G_OBJECT_CLASS (klass); + gstelement_class = GST_ELEMENT_CLASS (klass); + gstbasesrc_class = (GstBaseSrcClass *) klass; + gstpushsrc_class = (GstPushSrcClass *) klass; + gobject_class->set_property = gst_xv_image_src_set_property; + gobject_class->get_property = gst_xv_image_src_get_property; + gobject_class->finalize = gst_xv_image_src_finalize; + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&srctemplate)); + gst_element_class_set_details_simple (gstelement_class, + "XServer Display FB video source", "Source/video", + "Receive frame buffer data from XServer and passes to next element", + "Hyunjun Ko "); + + gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_xv_image_src_start); + gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_xv_image_src_stop); + gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_xv_image_src_unlock); + gstbasesrc_class->unlock_stop = + GST_DEBUG_FUNCPTR (gst_xv_image_src_unlock_stop); + gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_xv_image_src_get_size); + gstbasesrc_class->is_seekable = + GST_DEBUG_FUNCPTR (gst_xv_image_src_is_seekable); + gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_xv_image_src_query); + gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_xv_image_src_setcaps); + gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_xv_image_src_create); + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_xv_image_src_change_state); + + gst_xv_image_src_signals[SIGNAL_VIDEO_WITH_UI] = + g_signal_new ("video-with-ui", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstXVImageSrcClass, video_with_ui), + NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); + + gst_xv_image_src_signals[SIGNAL_VIDEO_ONLY] = + g_signal_new ("video-only", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstXVImageSrcClass, video_only), NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); + + gst_xv_image_src_signals[SIGNAL_SELECTION_NOTIFY] = + g_signal_new ("selection-notify", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstXVImageSrcClass, selection_notify), + NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); +} + +static GstStateChangeReturn +gst_xv_image_src_change_state (GstElement * element, GstStateChange transition) +{ + GstXVImageSrc *src = GST_XV_IMAGE_SRC (element); + + GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE; + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + GST_WARNING_OBJECT (src, "GST_STATE_CHANGE_NULL_TO_READY"); + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + GST_WARNING_OBJECT (src, "GST_STATE_CHANGE_READY_TO_PAUSED"); + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + GST_WARNING_OBJECT (src, "GST_STATE_CHANGE_PAUSED_TO_PLAYING"); + //src->pause_cond_var = FALSE; + //g_cond_signal(src->pause_cond); + break; + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + GST_WARNING_OBJECT (src, "GST_STATE_CHANGE_PLAYING_TO_PAUSED: START"); + //src->pause_cond_var = TRUE; + //g_cond_wait(src->pause_resp, src->pause_resp_lock); + GST_WARNING_OBJECT (src, "GST_STATE_CHANGE_PLAYING_TO_PAUSED: End"); + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + GST_WARNING_OBJECT (src, "GST_STATE_CHANGE_PAUSED_TO_READY"); + //src->thread_return = TRUE; + //g_cond_signal(src->pause_cond); + //g_cond_signal(src->queue_cond); + break; + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + + result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + return result; +} + +static gboolean +gst_xv_image_src_get_frame_size (int fourcc, int width, int height, + unsigned int *outsize) +{ + switch (fourcc) { +/* case GST_MAKE_FOURCC('I','4','2','0'): // V4L2_PIX_FMT_YUV420 + *outsize = GST_ROUND_UP_4 (width) * GST_ROUND_UP_2 (height); + *outsize += 2 * ((GST_ROUND_UP_8 (width) / 2) * (GST_ROUND_UP_2 (height) / 2)); + break;*/ + case GST_MAKE_FOURCC ('S', 'N', '1', '2'): // V4L2_PIX_FMT_NV12 non-linear + case GST_MAKE_FOURCC ('S', 'T', '1', '2'): // V4L2_PIX_FMT_NV12 tiled non-linear + GST_INFO ("SN12 or ST12"); + *outsize = GST_ROUND_UP_4 (width) * GST_ROUND_UP_2 (height); + *outsize += (GST_ROUND_UP_4 (width) * height) / 2; + break; + case GST_MAKE_FOURCC ('R', 'G', 'B', '4'): + /* jpeg size can't be calculated here. */ + *outsize = width * height * 4; + break; + default: + /* unkown format!! */ + *outsize = 0; + return FALSE; + } + return TRUE; +} + +static gboolean +gst_xv_image_src_parse_caps (const GstCaps * caps, guint32 * fourcc, + gint * width, gint * height, gint * rate_numerator, gint * rate_denominator, + unsigned int *framesize) +{ + const GstStructure *structure; + GstPadLinkReturn ret = TRUE; + const GValue *framerate; + const char *media_type = NULL; + + if (gst_caps_get_size (caps) < 1) + return FALSE; + + GST_INFO ("xvimagesrc src caps:%" GST_PTR_FORMAT, caps); + + structure = gst_caps_get_structure (caps, 0); + ret = gst_structure_get_int (structure, "width", width); + if (!ret) { + GST_ERROR ("xvimagesrc width not specified in caps"); + goto error; + } + + ret = gst_structure_get_int (structure, "height", height); + if (!ret) { + GST_ERROR ("xvimagesrc height not specified in caps"); + goto error; + } + + media_type = gst_structure_get_name (structure); + if (media_type == NULL) { + GST_ERROR ("xvimagesrc media type not specified in caps"); + goto error; + } + + framerate = gst_structure_get_value (structure, "framerate"); + if (framerate) { + *rate_numerator = gst_value_get_fraction_numerator (framerate); + *rate_denominator = gst_value_get_fraction_denominator (framerate); + } else { + GST_ERROR ("xvimagesrc frametype not specified in caps"); + goto error; + } + + if (g_strcmp0 (media_type, "video/x-raw") == 0) { + GST_INFO ("media_type is video/x-raw"); + guint32 format = FOURCC_SN12; + +#if 0 + ret = gst_structure_get_uint (structure, "format", &format); + if (!ret) + GST_DEBUG + ("xvimagesrc format not specified in caps, SN12 selected as default"); +#endif + const gchar * sformat = NULL; + + sformat = gst_structure_get_string(structure, "format"); + if (!sformat) { + GST_WARNING ("xvimagesrc format not specified in caps"); + } else { + format = FOURCC(sformat[0],sformat[1],sformat[2],sformat[3]); + } + + ret = gst_xv_image_src_get_frame_size (format, *width, *height, framesize); + if (!ret) { + GST_ERROR ("xvimagesrc unsupported format type specified in caps"); + goto error; + } + + *fourcc = format; + } + return TRUE; +/* ERRORS */ +error: + return FALSE; +} + +static gboolean +gst_xv_image_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps) +{ + gboolean res = TRUE; + gint width, height, rate_denominator, rate_numerator; + GstXVImageSrc *src; + + src = GST_XV_IMAGE_SRC (bsrc); + + res = gst_xv_image_src_parse_caps (caps, &src->format_id, &width, &height, + &rate_numerator, &rate_denominator, &src->framesize); + if (res) { + /* looks ok here */ + src->width = width; + src->height = height; + src->rate_numerator = rate_numerator; + src->rate_denominator = rate_denominator; + GST_DEBUG_OBJECT (src, "size %dx%d, %d/%d fps, framesize : %d", + src->width, src->height, + src->rate_numerator, src->rate_denominator, src->framesize); + + if (src->rate_numerator) { + src->sleep_base_time = + (long) (((int) (1000 / src->rate_numerator)) * 1000); + src->sleep_limit_time = (long) (-1 * src->sleep_base_time); + } + } + + xvimagesrc_thread_start (src); + return res; +} + +static void +gst_xv_image_src_init (GstXVImageSrc * src) +{ + src->format_id = 0; + src->running_time = GST_CLOCK_TIME_NONE; + src->frame_duration = GST_CLOCK_TIME_NONE; + src->virtual = NULL; + src->pixmap = 0; + src->gc = NULL; + src->bo = NULL; + src->dri2_buffers = NULL; + src->buf_share_method = BUF_SHARE_METHOD_TIZEN_BUFFER; + src->queue_lock = g_mutex_new (); + src->queue = g_queue_new (); + src->queue_cond = g_cond_new (); + src->cond_lock = g_mutex_new (); + src->buffer_cond = g_cond_new (); + src->buffer_cond_lock = g_mutex_new (); + src->dpy_lock = g_mutex_new (); + src->drm_fd = -1; + src->current_data_type = VIDEO_TYPE_VIDEO_WITH_UI; + src->new_data_type = VIDEO_TYPE_VIDEO_WITH_UI; + src->get_image_overtime = 0; + src->get_image_overtime_cnt = 0; + src->gemname_cnt = 0; + src->tz_enable = 0; + src->sleep_base_time = 0; + src->sleep_limit_time = 0; + + drm_init (src); + gst_base_src_set_live (GST_BASE_SRC (src), TRUE); +} + +static void +gst_xv_image_src_finalize (GObject * gobject) +{ + GstXVImageSrc *src = GST_XV_IMAGE_SRC (gobject); + GST_DEBUG_OBJECT (src, "finalize"); + g_mutex_free (src->queue_lock); + drm_finalize (src); + G_OBJECT_CLASS (parent_class)->finalize (gobject); +} + +static void +drm_init (GstXVImageSrc * src) +{ + Display *dpy; + int eventBase, errorBase; + int dri2Major, dri2Minor; + char *driverName, *deviceName; + struct drm_auth auth_arg = { 0 }; + + src->drm_fd = -1; + dpy = XOpenDisplay (0); + + /* DRI2 */ + if (!DRI2QueryExtension (dpy, &eventBase, &errorBase)) { + GST_ERROR ("DRI2QueryExtension !!"); + return; + } + if (!DRI2QueryVersion (dpy, &dri2Major, &dri2Minor)) { + GST_ERROR ("DRI2QueryVersion !!"); + return; + } + if (!DRI2Connect (dpy, RootWindow (dpy, DefaultScreen (dpy)), &driverName, + &deviceName)) { + GST_ERROR ("DRI2Connect !!"); + return; + } + GST_INFO ("Open drm device : %s", deviceName); + + /* get the drm_fd though opening the deviceName */ + src->drm_fd = open (deviceName, O_RDWR); + if (src->drm_fd < 0) { + GST_ERROR ("cannot open drm device (%s)", deviceName); + return; + } + + /* get magic from drm to authentication */ + if (ioctl (src->drm_fd, DRM_IOCTL_GET_MAGIC, &auth_arg)) { + GST_ERROR ("cannot get drm auth magic"); + close (src->drm_fd); + src->drm_fd = -1; + return; + } + if (!DRI2Authenticate (dpy, RootWindow (dpy, DefaultScreen (dpy)), + auth_arg.magic)) { + GST_ERROR ("cannot get drm authentication from X"); + close (src->drm_fd); + src->drm_fd = -1; + return; + } +} + +static void +drm_finalize (GstXVImageSrc * src) +{ + if (src->drm_fd >= 0) { + close (src->drm_fd); + src->drm_fd = -1; + } +} + +static tbm_bo +drm_convert_gem_to_bo (tbm_bufmgr bufmgr, unsigned int gem_name) +{ + tbm_bo ret = NULL; + + ret = tbm_bo_import (bufmgr, gem_name); + if (ret == NULL) { + GST_ERROR ("[Error] : cannot import bo (key:%d)", gem_name); + } + + return ret; +} + +static gint32 +drm_convert_gem_to_fd (int *gemname_cnt, int drm_fd, unsigned int name, + void *data, void **virtual_address, guint * buf_size) +{ + g_return_val_if_fail ((data != NULL), 0); + int count = 0; + gint32 fd = 0; + count = *gemname_cnt; + GST_DEBUG ("gamname_cnt = %d", count); + GST_DEBUG ("name = %u", name); + + + GEM_MMAP *xv_gem_mmap = NULL; + xv_gem_mmap = (GEM_MMAP *) data; + + if (count < GEM_NAME_MAX) { + int i = 0; + + for (i = 0; i < GEM_NAME_MAX; i++) { + if (name == xv_gem_mmap->name[i]) + goto PASS; + } + + struct drm_prime_handle prime; + struct drm_gem_open gem_open; + struct drm_exynos_gem_mmap gem_mmap; //for virtual address + + memset (&gem_open, 0, sizeof (struct drm_gem_open)); + gem_open.name = name; + if (ioctl (drm_fd, DRM_IOCTL_GEM_OPEN, &gem_open)) { + GST_ERROR ("Gem Open failed"); + return 0; + } + + memset (&prime, 0, sizeof (struct drm_prime_handle)); + prime.handle = gem_open.handle; + prime.flags = DRM_CLOEXEC; + + /*get gem_open handle */ + xv_gem_mmap->handle[count] = gem_open.handle; + GST_DEBUG ("gem_open.handle =%d, xv_gem_mmap->handle[count]=%d", + gem_open.handle, xv_gem_mmap->handle[count]); + + /*get virtual address */ + /*set name */ + xv_gem_mmap->name[count] = name; + memset (&gem_mmap, 0, sizeof (struct drm_exynos_gem_mmap)); + gem_mmap.handle = prime.handle; + gem_mmap.size = gem_open.size; + + /*set size */ + xv_gem_mmap->buffer_size[count] = gem_mmap.size; + if (drmIoctl (drm_fd, DRM_IOCTL_EXYNOS_GEM_MMAP, &gem_mmap) != 0) { + GST_ERROR ("Gem mmap failed [handle %d, size %lld]", gem_mmap.handle, + gem_mmap.size); + return 0; + } + + /*set virtual address */ + xv_gem_mmap->address[count] = (void *) (gem_mmap.mapped); + GST_DEBUG ("%u - Virtual address[%d] = %p size=%d ", name, count, + xv_gem_mmap->address[count], xv_gem_mmap->buffer_size[count]); + + /*get fd */ + if (ioctl (drm_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime) < 0) { + GST_ERROR ("Gem Handle to Fd failed"); + return 0; + } + + xv_gem_mmap->fd[count] = prime.fd; + GST_DEBUG ("fd = %d", xv_gem_mmap->fd[count]); + } + + if (count < GEM_NAME_MAX) { + count++; + *gemname_cnt = count; + } + +PASS: + if (name == xv_gem_mmap->name[0]) { + *virtual_address = xv_gem_mmap->address[0]; + fd = xv_gem_mmap->fd[0]; + *buf_size = xv_gem_mmap->buffer_size[0]; + } else if (name == xv_gem_mmap->name[1]) { + *virtual_address = xv_gem_mmap->address[1]; + fd = xv_gem_mmap->fd[1]; + *buf_size = xv_gem_mmap->buffer_size[1]; + } else if (name == xv_gem_mmap->name[2]) { + *virtual_address = xv_gem_mmap->address[2]; + fd = xv_gem_mmap->fd[2]; + *buf_size = xv_gem_mmap->buffer_size[2]; + } else if (name == xv_gem_mmap->name[3]) { + *virtual_address = xv_gem_mmap->address[3]; + fd = xv_gem_mmap->fd[3]; + *buf_size = xv_gem_mmap->buffer_size[3]; + } else if (name == xv_gem_mmap->name[4]) { + *virtual_address = xv_gem_mmap->address[4]; + fd = xv_gem_mmap->fd[4]; + *buf_size = xv_gem_mmap->buffer_size[4]; + } else if (name == xv_gem_mmap->name[5]) { + *virtual_address = xv_gem_mmap->address[5]; + fd = xv_gem_mmap->fd[5]; + *buf_size = xv_gem_mmap->buffer_size[5]; + } else if (name == xv_gem_mmap->name[6]) { + *virtual_address = xv_gem_mmap->address[6]; + fd = xv_gem_mmap->fd[6]; + *buf_size = xv_gem_mmap->buffer_size[6]; + } else if (name == xv_gem_mmap->name[7]) { + *virtual_address = xv_gem_mmap->address[7]; + fd = xv_gem_mmap->fd[7]; + *buf_size = xv_gem_mmap->buffer_size[7]; + } else if (name == xv_gem_mmap->name[8]) { + *virtual_address = xv_gem_mmap->address[8]; + fd = xv_gem_mmap->fd[8]; + *buf_size = xv_gem_mmap->buffer_size[8]; + } else if (name == xv_gem_mmap->name[9]) { + *virtual_address = xv_gem_mmap->address[9]; + fd = xv_gem_mmap->fd[9]; + *buf_size = xv_gem_mmap->buffer_size[9]; + } + + GST_DEBUG ("virtual_address = %p (size: %d) fd = %d", + *virtual_address, *buf_size, fd); + return fd; +} + +static void +gst_xv_image_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + //GstXVImageSrc *src = GST_XV_IMAGE_SRC (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + + return; +} + +static void +gst_xv_image_src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + //GstXVImageSrc *src = GST_XV_IMAGE_SRC (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + + return; +} + +static gboolean +gst_xv_image_src_get_timeinfo (GstXVImageSrc * src, GstBuffer * buffer) +{ + int fps_nu = 0; + int fps_de = 0; + GstClockTime timestamp = GST_CLOCK_TIME_NONE; + GstClockTime duration = GST_CLOCK_TIME_NONE; + GstClock *clock; + + if (!src || !buffer) { + GST_WARNING ("Invalid pointer [handle:%p, buffer:%p]", src, buffer); + return FALSE; + } + + clock = gst_element_get_clock (GST_ELEMENT (src)); + if (clock) { + timestamp = gst_clock_get_time (clock); + timestamp -= gst_element_get_base_time (GST_ELEMENT (src)); + gst_object_unref (clock); + } else { + /* not an error not to have a clock */ + timestamp = GST_CLOCK_TIME_NONE; + } + + /* if we have a framerate adjust timestamp for frame latency */ + if ((int) ((float) src->rate_numerator / (float) src->rate_denominator) <= 0) { + /*if fps is zero, auto fps mode */ + fps_nu = 0; + fps_de = 1; + } else { + fps_nu = 1; + fps_de = + (int) ((float) src->rate_numerator / (float) src->rate_denominator); + } + + if (fps_nu > 0 && fps_de > 0) { + GstClockTime latency; + latency = gst_util_uint64_scale_int (GST_SECOND, fps_nu, fps_de); + duration = latency; + } + + GST_BUFFER_TIMESTAMP (buffer) = timestamp; + GST_BUFFER_DURATION (buffer) = duration; + + return TRUE; +} + +#ifdef COUNT_FRAMES +static int fps = 0; + +static gchar * +get_current_system_time () +{ + gchar target[10] = { 0, }; + time_t t; + struct tm tm; + + t = time (NULL); + tzset (); + /*localtimer_r : available since libc 5.2.5 */ + if (localtime_r (&t, &tm) == NULL) { + return NULL; + } + snprintf (target, sizeof (target), "%02i:%02i:%02i", tm.tm_hour, tm.tm_min, + tm.tm_sec); + return g_strdup (target); +} +#endif + +static void +gst_xv_get_image_sleep (void *asrc, long duration) +{ + GST_INFO ("end_time duration=%ld", duration); + if (duration < 0) + return; + + GstXVImageSrc *src = (GstXVImageSrc *) asrc; + g_return_if_fail (src != NULL); + + long sleep_time = 0; + sleep_time = src->sleep_base_time - duration; + + if (sleep_time < 0) { + src->get_image_overtime_cnt++; + src->get_image_overtime += sleep_time; + + if (src->get_image_overtime_cnt > 2) + src->get_image_overtime = 0; + + if (src->get_image_overtime <= src->sleep_limit_time) + src->get_image_overtime = 0; + } else if (sleep_time > 0) { + src->get_image_overtime_cnt = 0; + sleep_time = sleep_time + src->get_image_overtime; + src->get_image_overtime = (sleep_time < 0) ? sleep_time : 0; + + if (sleep_time > 0) { + GST_INFO ("end_time : sleep_time = %ld", sleep_time); + usleep (sleep_time); + } + } +} + +static GstFlowReturn +gst_xv_image_src_create (GstPushSrc * psrc, GstBuffer ** buffer) +{ + GstXVImageSrc *src; + GstXvImageOutBuffer *outbuf = NULL; + + src = GST_XV_IMAGE_SRC (psrc); + g_mutex_lock (src->queue_lock); + + if (g_queue_is_empty (src->queue)) { + g_mutex_unlock (src->queue_lock); + g_cond_wait (src->queue_cond, src->cond_lock); + + g_mutex_lock (src->queue_lock); + outbuf = (GstXvImageOutBuffer *) g_queue_pop_head (src->queue); + g_mutex_unlock (src->queue_lock); + } else { + GstXvImageOutBuffer *tempbuf = NULL; + while ((tempbuf = + (GstXvImageOutBuffer *) g_queue_pop_head (src->queue)) != NULL) { + /* To reduce latency, skipping the old frames and submitting only latest frames */ + outbuf = tempbuf; + g_mutex_unlock (src->queue_lock); + } + } + + if (outbuf == NULL) + return GST_FLOW_ERROR; + + GST_INFO ("gem_name=%d, fd_name=%d, Time stamp of the buffer is %" + GST_TIME_FORMAT, outbuf->YBuf, outbuf->fd_name, + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf->buffer))); + + *buffer = outbuf->buffer; + +#ifdef COUNT_FRAMES + gchar *current_time = NULL; + current_time = get_current_system_time (); + if (strncmp (current_time, old_time, 10) == 0) { + fps++; + strncpy (old_time, current_time, 10); + } else { + g_printf ("xvimagesrc %s - fps : %d\n", old_time, fps); + fps = 1; + strncpy (old_time, current_time, 10); + } +#endif + + return GST_FLOW_OK; +} + +static gboolean +xvimagesrc_thread_start (GstXVImageSrc * src) +{ + GError *error; + if (!src->updates_thread) + src->updates_thread = + g_thread_create ((GThreadFunc) gst_xv_image_src_update_thread, src, + TRUE, &error); + else + GST_LOG_OBJECT (src, "The thread function already running"); + return TRUE; +} + +static gboolean +gst_xv_image_src_start (GstBaseSrc * bsrc) +{ + GstXVImageSrc *src = GST_XV_IMAGE_SRC (bsrc); + if (src->format_id) + xvimagesrc_thread_start (src); + return TRUE; +} + +gboolean +signal_emit_func (void *asrc) +{ + GstXVImageSrc *src = (GstXVImageSrc *) asrc; + if (src->current_data_type == VIDEO_TYPE_VIDEO_ONLY) { + g_signal_emit (src, gst_xv_image_src_signals[SIGNAL_VIDEO_ONLY], 0, NULL); + } else if (src->current_data_type == VIDEO_TYPE_VIDEO_WITH_UI) { + g_signal_emit (src, gst_xv_image_src_signals[SIGNAL_VIDEO_WITH_UI], 0, + NULL); + } + return FALSE; +} + +static gboolean +signal_selection_emit_func (void *asrc) +{ + GstXVImageSrc *src = (GstXVImageSrc *) asrc; + + g_signal_emit (src, gst_xv_image_src_signals[SIGNAL_SELECTION_NOTIFY], 0, + NULL); + + return FALSE; +} + +static int +gst_xvimagesrc_handle_xerror (Display * display, XErrorEvent * xevent) +{ + char error_msg[1024]; + + XGetErrorText (display, xevent->error_code, error_msg, 1024); + GST_DEBUG ("XError. error: %s", error_msg); + error_caught = TRUE; + return 0; +} + +static void +gst_xv_image_out_buffer_unref (gpointer userdata) +{ + Atom atom_retbuf = 0; + //GstXVImageSrc *xvimagesrc = userdata; + GstXvImageOutBuffer *buffer = userdata; + + GST_WARNING ("Buffer unref!!"); + + GST_WARNING ("Unref bo: %p %p", buffer->bo[0], buffer->bo[1]); + tbm_bo_unref (buffer->bo[0]); + tbm_bo_unref (buffer->bo[1]); + + g_mutex_lock (buffer->xvimagesrc->dpy_lock); + atom_retbuf = + XInternAtom (buffer->xvimagesrc->dpy, + "_USER_WM_PORT_ATTRIBUTE_RETURN_BUFFER", False); + + /* data->YBuf is gemname, refer to drm_convert_gem_to_fd */ + XvSetPortAttribute (buffer->xvimagesrc->dpy, buffer->xvimagesrc->p, + atom_retbuf, buffer->YBuf); + + g_mutex_unlock (buffer->xvimagesrc->dpy_lock); + g_cond_signal (buffer->xvimagesrc->buffer_cond); + +#ifdef DEBUG_BUFFER + int i = 0; + for (i = 0; i < 5; i++) { + if (value[i] == buffer->YBuf) { + value[i] = 0; + GST_ERROR ("value[%d]=%d", i, value[i]); + } + } +#endif + + return; +} + +static void * +gst_xv_image_src_update_thread (void *asrc) +{ + GstXVImageSrc *src = (GstXVImageSrc *) asrc; + Atom atom_data_type = 0; + Atom atom_display = 0; + Atom atom_secure = 0, atom_capture = 0; + + g_return_val_if_fail ((src != NULL), NULL); + + struct drm_gem_close gem_close; + int i = 0; + GEM_MMAP *xv_gem_mmap = NULL; + xv_gem_mmap = (GEM_MMAP *) malloc (sizeof (GEM_MMAP)); + g_return_val_if_fail ((xv_gem_mmap != NULL), NULL); + + memset (xv_gem_mmap, 0, sizeof (GEM_MMAP)); + + GST_LOG_OBJECT (src, "The thread function start"); + int damage_err_base = 0; + Atom atom_format = 0; + src->dpy = XOpenDisplay (NULL); + + src->p = port_get (src, src->format_id); + if (src->p < 0) + goto finish; + + /*src->width and src->height is set by caps info */ + GST_LOG_OBJECT (src, "width and height of caps : %dx%d ", src->width, + src->height); + if (src->width == 0 || src->height == 0) { + GST_ERROR_OBJECT (src, "width or height is 0"); + goto finish; + } + + src->pixmap = pixmap_create (src, src->dpy, src->width, src->height); + if (src->pixmap <= 0) { + GST_ERROR_OBJECT (src, "Failed to create pixmap"); + goto finish; + } + + src->gc = XCreateGC (src->dpy, src->pixmap, 0, 0); + if (src->gc == NULL) { + GST_ERROR_OBJECT (src, "Failed to create GC"); + goto finish; + } + + src->bufmgr = bufmgr_get (src->dpy, src->pixmap); + if (!src->bufmgr) + goto finish; + + if (!XDamageQueryExtension (src->dpy, &src->damage_base, &damage_err_base)) { + GST_ERROR_OBJECT (src, "XDamageQueryExtension failed"); + goto finish; + } + + src->damage = XDamageCreate (src->dpy, src->pixmap, XDamageReportNonEmpty); + atom_format = XInternAtom (src->dpy, "_USER_WM_PORT_ATTRIBUTE_FORMAT", False); + atom_capture = + XInternAtom (src->dpy, "_USER_WM_PORT_ATTRIBUTE_CAPTURE", False); + atom_secure = XInternAtom (src->dpy, "_USER_WM_PORT_ATTRIBUTE_SECURE", False); + atom_display = + XInternAtom (src->dpy, "_USER_WM_PORT_ATTRIBUTE_DISPLAY", False); + + XvSetPortAttribute (src->dpy, src->p, atom_format, src->format_id); + XvSetPortAttribute (src->dpy, src->p, atom_capture, 2); + XvSetPortAttribute (src->dpy, src->p, atom_display, 1); + + /*get data type */ + atom_data_type = + XInternAtom (src->dpy, "_USER_WM_PORT_ATTRIBUTE_DATA_TYPE", False); + XvSelectPortNotify (src->dpy, src->p, 1); + XvGetPortAttribute (src->dpy, src->p, atom_data_type, &(src->new_data_type)); +#if 0 + /*set Xorg write-back hz */ + atom_fps = XInternAtom (src->dpy, "_USER_WM_PORT_ATTRIBUTE_FPS", False); + GST_DEBUG ("frame rate of caps %d", src->rate_numerator); + XvSetPortAttribute (src->dpy, src->p, atom_fps, src->rate_numerator); + GST_DEBUG ("gst_xv_image_src_update_thread XvSetPortAttribute !!"); +#endif + + struct timeval start_time, end_time; + long duration; + long starttime, endtime; + GTimeVal timeout; + XEvent ev; + void *virtual_address = NULL; + guint buf_size_Y = 0; + guint buf_size_Cb = 0; + int (*handler) (Display *, XErrorEvent *); + GstXvImageOutBuffer *outbuf = NULL; + + gboolean got_display_select_req = FALSE; + + while (!src->thread_return) { + duration = 0; + starttime = 0; + endtime = 0; + start_time.tv_sec = 0; + start_time.tv_usec = 0; + end_time.tv_sec = 0; + end_time.tv_usec = 0; + gettimeofday (&start_time, NULL); + + virtual_address = NULL; + duration = 0; + outbuf = NULL; + + g_mutex_lock (src->dpy_lock); + XSync (src->dpy, 0); + g_mutex_unlock (src->dpy_lock); + error_caught = FALSE; + handler = XSetErrorHandler (gst_xvimagesrc_handle_xerror); + + g_mutex_lock (src->dpy_lock); + XvPutStill (src->dpy, src->p, src->pixmap, src->gc, 0, 0, src->width, + src->height, 0, 0, src->width, src->height); + XSync (src->dpy, 0); + g_mutex_unlock (src->dpy_lock); + + if (error_caught) { + GST_ERROR + ("gst_xv_image_src_update_thread error_caught is TRUE, X is out of buffers"); + error_caught = FALSE; + XSetErrorHandler (handler); + g_get_current_time (&timeout); + g_time_val_add (&timeout, BUFFER_COND_WAIT_TIMEOUT); + if (!g_cond_timed_wait (src->buffer_cond, src->buffer_cond_lock, + &timeout)) { + GST_ERROR ("skip wating"); + } else { + GST_ERROR ("Signal received"); + } + continue; + } + + /*reset error handler */ + error_caught = FALSE; + XSetErrorHandler (handler); + + next_event: + g_mutex_lock (src->dpy_lock); + XNextEvent (src->dpy, &ev); /* wating for x event */ + g_mutex_unlock (src->dpy_lock); + + if (ev.type == (src->damage_base + XDamageNotify)) { + XDamageNotifyEvent *damage_ev = (XDamageNotifyEvent *) & ev; + GST_INFO ("gst_xv_image_src_update_thread XDamageNotifyEvent"); + + g_mutex_lock (src->dpy_lock); + if (damage_ev->drawable == src->pixmap) { + pixmap_update (src, src->dpy, src->bufmgr, src->pixmap, + damage_ev->area.x, + damage_ev->area.y, damage_ev->area.width, damage_ev->area.height); + GST_INFO ("gst_xv_image_src_update_thread pixmap_update"); + } + + XDamageSubtract (src->dpy, src->damage, None, None); + g_mutex_unlock (src->dpy_lock); + } else if (ev.type == SelectionClear) { + /* Added to handle display selection notify */ + //XSelectionEvent *selection_ev = (XSelectionEvent *) & ev; + + GST_ERROR ("ev.type : %d SelectionClear", ev.type); + //g_timeout_add(1, signal_selection_emit_func, src); + } else if (ev.type == SelectionRequest) { + XSelectionRequestEvent *selection_ev = (XSelectionRequestEvent *) & ev; + + GST_ERROR ("ev.type : %d SelectionRequest", ev.type); + src->requestor = selection_ev->requestor; + src->selection = selection_ev->selection; + src->target = selection_ev->target; + src->property = selection_ev->property; + + got_display_select_req = TRUE; + g_timeout_add (1, signal_selection_emit_func, src); + } else if (ev.type == SelectionNotify) { + //XSelectionEvent *selection_ev = (XSelectionEvent *) & ev; + + GST_ERROR ("ev.type : %d SelectionNotify", ev.type); + //g_timeout_add(1, signal_selection_emit_func, src); + } else if (ev.type == (src->evt_base + XvPortNotify)) { + XvPortNotifyEvent *notify_ev = (XvPortNotifyEvent *) & ev; + + if (notify_ev->attribute == atom_secure) { + GST_WARNING ("secure attr changed : %s \n", + ((int) notify_ev->value) ? "Secure" : "Normal"); + src->tz_enable = (int) notify_ev->value; + GST_WARNING ("src->tz_enable = %d", src->tz_enable); + } else if (notify_ev->attribute == atom_data_type) { + /* got a port notify, data_type */ + src->new_data_type = (int) notify_ev->value; + if (src->current_data_type != src->new_data_type) { + src->current_data_type = src->new_data_type; + GST_WARNING ("current_data_type : %s \n", + (src->current_data_type) ? "Video" : "UI+Video"); + g_timeout_add (1, signal_emit_func, src); + } + } + goto next_event; + } + + if (!src->virtual) + continue; + if (src->format_id == FOURCC_RGB32) { + outbuf = (GstXvImageOutBuffer *) malloc (sizeof (GstXvImageOutBuffer)); + outbuf->buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, + src->virtual, src->framesize, 0, src->framesize, NULL, NULL); +#if 0 + void *tmp_data = NULL; + tmp_data = (void *)malloc(buf_size_Y+buf_size_Cb); + memset (tmp_data, 0x00, buf_size_Y+buf_size_Cb); + + memcpy (tmp_data, psimgb->a[0], buf_size_Y); + memcpy (tmp_data+buf_size_Y, psimgb->a[1], buf_size_Cb); + + outbuf->buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, + tmp_data, buf_size_Y+buf_size_Cb, 0, buf_size_Y+buf_size_Cb, (gpointer) outbuf, + gst_xv_image_out_buffer_unref); + + free (tmp_data); +/* + GstBuffer *new_buf = NULL; + new_buf = gst_buffer_new_and_alloc (buf_size_Y+buf_size_Cb); + gst_buffer_set_size (new_buf, buf_size_Y+buf_size_Cb); + + GstMapInfo map; + gst_buffer_map (new_buf, &map, GST_MAP_READ); + memcpy (map.data, psimgb->a[0], buf_size_Y); + memcpy (map.data+buf_size_Y, psimgb->a[1], buf_size_Cb); + + outbuf->buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, + map.data, buf_size_Y+buf_size_Cb, 0, buf_size_Y+buf_size_Cb, (gpointer) outbuf, + gst_xv_image_out_buffer_unref); + + gst_buffer_unmap (new_buf, &map); + gst_buffer_unref (new_buf); +*/ + +#endif + } else if (src->format_id == FOURCC_SN12) { + XV_DATA_PTR data = (XV_DATA_PTR) src->virtual; + int error = XV_VALIDATE_DATA (data); + + outbuf = gst_xv_image_out_buffer_new (src); + if (!outbuf) { + GST_ERROR ("Out of memory"); + continue; + } + + if (error == XV_HEADER_ERROR) + GST_ERROR ("XV_HEADER_ERROR\n"); + else if (error == XV_VERSION_MISMATCH) + GST_ERROR ("XV_VERSION_MISMATCH\n"); + else { + SCMN_IMGB *psimgb = NULL; + psimgb = (SCMN_IMGB *) malloc (sizeof (SCMN_IMGB)); + if (psimgb == NULL) { + GST_ERROR_OBJECT (src, "failed to alloc SCMN_IMGB"); + return NULL; + } + memset (psimgb, 0x00, sizeof (SCMN_IMGB)); + if (data->BufType == XV_BUF_TYPE_LEGACY) { + psimgb->p[0] = (void *) data->YBuf; + psimgb->p[1] = (void *) data->CbBuf; + psimgb->buf_share_method = BUF_SHARE_METHOD_PADDR; + psimgb->a[0] = NULL; + psimgb->a[1] = NULL; + } else if (data->BufType == XV_BUF_TYPE_DMABUF) { + if (src->buf_share_method == BUF_SHARE_METHOD_FD) { + psimgb->dmabuf_fd[0] = + drm_convert_gem_to_fd (&src->gemname_cnt, src->drm_fd, data->YBuf, + xv_gem_mmap, &virtual_address, &buf_size_Y); + psimgb->a[0] = virtual_address; + GST_WARNING_OBJECT (src, + "YBuf gem to dmabuf_fd[0]:%d virtual_address : %p size : %d", + psimgb->dmabuf_fd[0], psimgb->a[0], buf_size_Y); + + psimgb->dmabuf_fd[1] = + drm_convert_gem_to_fd (&src->gemname_cnt, src->drm_fd, + data->CbBuf, xv_gem_mmap, &virtual_address, &buf_size_Cb); + psimgb->a[1] = virtual_address; + GST_WARNING_OBJECT (src, + "CbBuf gem to dmabuf_fd[1]:%d virtual_address : %p size: %d", + psimgb->dmabuf_fd[1], psimgb->a[1], buf_size_Cb); + psimgb->buf_share_method = BUF_SHARE_METHOD_FD; + } else if (src->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER) { + psimgb->buf_share_method = BUF_SHARE_METHOD_TIZEN_BUFFER; + psimgb->bo[0] = drm_convert_gem_to_bo (src->bufmgr, data->YBuf); + psimgb->bo[1] = drm_convert_gem_to_bo (src->bufmgr, data->CbBuf); + GST_WARNING_OBJECT (src, "BO : %p %p", psimgb->bo[0], psimgb->bo[1]); + + outbuf->bo[0] = psimgb->bo[0]; + outbuf->bo[1] = psimgb->bo[1]; + } + } + + psimgb->w[0] = src->width; + psimgb->h[0] = src->height; + psimgb->cs = SCMN_CS_NV12; + psimgb->w[1] = src->width; + psimgb->h[1] = src->height >> 1; + + psimgb->s[0] = GST_ROUND_UP_16 (psimgb->w[0]); + psimgb->e[0] = GST_ROUND_UP_16 (psimgb->h[0]); + psimgb->s[1] = GST_ROUND_UP_16 (psimgb->w[1]); + psimgb->e[1] = GST_ROUND_UP_16 (psimgb->h[1]); + + psimgb->tz_enable = 0; + + outbuf->buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, + src->virtual, src->framesize, 0, src->framesize, (gpointer) outbuf, + gst_xv_image_out_buffer_unref); + gst_buffer_append_memory (outbuf->buffer, + gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, psimgb, + sizeof (*psimgb), 0, sizeof (*psimgb), psimgb, g_free)); + + outbuf->YBuf = data->YBuf; + outbuf->fd_name = psimgb->dmabuf_fd[0]; + +#ifdef DEBUG_BUFFER + for (i = 0; i < 5; i++) { + if (value[value_count] == outbuf->YBuf) { + GST_ERROR ("ERROR: value[%d](%d)==YBUf(%d)", value_count, + value[value_count], outbuf->YBuf); + } + } + value[value_count] = outbuf->YBuf; + GST_ERROR ("value[%d]=%d", value_count, value[value_count]); + if (value_count < 4) { + value_count++; + } else { + value_count = 0; + } +#endif + +#ifdef _MAKE_DUMP + if (f_idx < 100) { + if (src->running_time > 14000000000 + && src->running_time < 20000000000) { + GST_ERROR ("Mem copy"); + if (virtual_address == NULL) { + GST_ERROR ("Mem virtual is NULL[%d]", f_idx); + } else { + //memcpy(g_dump_frame[f_idx++], psimgb->a[0], YUV_720_FRAME_SIZE); + //memcpy(g_dump_frame[f_idx++], virtual_address, YUV_VGA_FRAME_SIZE); + memcpy (g_dump_frame[f_idx], psimgb->a[0], 921600); + memcpy (g_dump_frame1[f_idx], psimgb->a[1], 462848); + f_idx++; + GST_ERROR ("Mem copy done[%d]", f_idx); + } + } + } else { + if (f_done == 0) { + GST_ERROR ("File DUMP!!"); + FILE *fp = NULL; + fp = fopen ("/root/frame.yuv", "a"); + int i = 0; + for (i = 0; i < 100; i++) { + fwrite (g_dump_frame[i], 921600, 1, fp); + fwrite (g_dump_frame1[i], 462848, 1, fp); + //fwrite(g_dump_frame[i], 1384448, 1, fp); + //fwrite(g_dump_frame[i], YUV_720_FRAME_SIZE, 1, fp); + //fwrite(g_dump_frame[i], YUV_VGA_FRAME_SIZE, 1, fp); + } + fclose (fp); + f_done = 1; + GST_ERROR ("File DUMP done!!"); + } + } +#endif + } + } + + if (!outbuf) + continue; + + gst_xv_image_src_get_timeinfo (src, outbuf->buffer); + if (GST_CLOCK_TIME_IS_VALID (src->running_time) + && GST_CLOCK_TIME_IS_VALID (src->frame_duration)) { + if (GST_BUFFER_TIMESTAMP (outbuf->buffer) < + (src->running_time + src->frame_duration - 6000000)) { + } + } + + src->running_time = GST_BUFFER_TIMESTAMP (outbuf->buffer); + src->frame_duration = GST_BUFFER_DURATION (outbuf->buffer); + g_mutex_lock (src->queue_lock); + g_queue_push_tail (src->queue, outbuf); + GST_INFO ("g_queue_push_tail"); + g_mutex_unlock (src->queue_lock); + g_cond_signal (src->queue_cond); + GST_INFO ("g_cond_signal"); + + if (src->virtual) + tbm_bo_unmap (src->bo); + src->virtual = NULL; + + if (src->bo) + tbm_bo_unref (src->bo); + src->bo = NULL; + + if (src->dri2_buffers) + free (src->dri2_buffers); + + src->dri2_buffers = NULL; + + gettimeofday (&end_time, NULL); + starttime = start_time.tv_usec; + endtime = end_time.tv_usec; + GST_INFO ("star_time: %ld, end_time:%ld", starttime, endtime); + + if (endtime > starttime) { + GST_INFO ("end_time > start_time"); + duration = endtime - starttime; + } else { + GST_INFO ("end_time.tv_usec < start_time.tv_usec"); + endtime = endtime + 1000000; + GST_INFO ("end_time =%ld", endtime); + duration = endtime - starttime; + } + GST_INFO ("end_time duration = %ld", duration); + + if (src->sleep_base_time > duration) + gst_xv_get_image_sleep (src, duration); + } + + for (i = 0; i < GEM_NAME_MAX; i++) { + /*gem munmap */ + if (xv_gem_mmap->address[i]) { + if (-1 == munmap (xv_gem_mmap->address[i], xv_gem_mmap->buffer_size[i])) { + GST_ERROR ("munmap failed"); + return NULL; + } + } + /*fd close */ + if (xv_gem_mmap->handle[i]) { + gem_close.handle = xv_gem_mmap->handle[i]; + if (ioctl (src->drm_fd, DRM_IOCTL_GEM_CLOSE, &gem_close)) { + GST_ERROR ("Gem Close failed"); + } + } + + if (xv_gem_mmap->fd[i]) { + close (xv_gem_mmap->fd[i]); + } + } + + if (xv_gem_mmap) { + free (xv_gem_mmap); + xv_gem_mmap = NULL; + } + + + GST_LOG_OBJECT (src, "The thread function cleanup"); + + XvStopVideo (src->dpy, src->p, src->pixmap); + + if (src->bufmgr) { + tbm_bufmgr_deinit (src->bufmgr); + src->bufmgr = NULL; + } + + if (src->p > 0) { + XvUngrabPort (src->dpy, src->p, 0); + src->p = 0; + } + + if (got_display_select_req) { + /* Notify miracast-destroyed to X */ + GST_WARNING_OBJECT (src, "There is display selection request"); + XEvent xev; + XSelectionEvent xnotify; + + xnotify.type = SelectionNotify; + xnotify.display = src->dpy; + xnotify.requestor = src->requestor; + xnotify.selection = src->selection; + xnotify.target = src->target; + xnotify.property = src->property; + xnotify.time = 0; + xnotify.send_event = True; + xnotify.serial = 0; + xev.xselection = xnotify; + if (XSendEvent (src->dpy, src->requestor, False, 0, &xev) < 0) { + GST_ERROR ("XSendEvent failed!"); + } else { + GST_INFO ("XSendEvent success!"); + } + } + + if (src->gc) { + XFreeGC (src->dpy, src->gc); + src->gc = NULL; + } + + if (src->pixmap > 0) { + XFreePixmap (src->dpy, src->pixmap); + src->pixmap = 0; + } + + if (src->dpy) { + XCloseDisplay (src->dpy); + src->dpy = NULL; + } + + GST_LOG_OBJECT (src, "The thread function stop"); + return NULL; +finish: + GST_LOG_OBJECT (src, "The thread function Error cleanup"); + + XvStopVideo (src->dpy, src->p, src->pixmap); + + if (src->bufmgr) + tbm_bufmgr_deinit (src->bufmgr); + src->bufmgr = NULL; + if (src->p > 0) + XvUngrabPort (src->dpy, src->p, 0); + src->p = 0; + if (src->gc) + XFreeGC (src->dpy, src->gc); + src->gc = NULL; + if (src->pixmap > 0) + XFreePixmap (src->dpy, src->pixmap); + src->pixmap = 0; + if (src->dpy) + XCloseDisplay (src->dpy); + src->dpy = NULL; + + GST_LOG_OBJECT (src, "The thread function Error stop"); + return NULL; +} + +static tbm_bufmgr +bufmgr_get (Display * dpy, Pixmap pixmap) +{ + int screen; + int drm_fd; + tbm_bufmgr bufmgr; + int eventBase, errorBase; + int dri2Major, dri2Minor; + char *driverName, *deviceName; + drm_magic_t magic; + + screen = DefaultScreen (dpy); + if (!DRI2QueryExtension (dpy, &eventBase, &errorBase)) { + GST_ERROR ("!!Error : DRI2QueryExtension !!"); + return NULL; + } + + if (!DRI2QueryVersion (dpy, &dri2Major, &dri2Minor)) { + GST_ERROR ("!!Error : DRI2QueryVersion !!"); + return NULL; + } + + if (!DRI2Connect (dpy, RootWindow (dpy, screen), &driverName, &deviceName)) { + GST_ERROR ("!!Error : DRI2Connect !!"); + if (driverName) + Xfree (driverName); + if (deviceName) + Xfree (deviceName); + return NULL; + } + + if (driverName) + Xfree (driverName); + + GST_DEBUG ("Open drm device : %s", deviceName); + + // get the drm_fd though opening the deviceName + drm_fd = open (deviceName, O_RDWR); + if (drm_fd < 0) { + GST_ERROR ("!!Error : cannot open drm device (%s)", deviceName); + if (deviceName) + Xfree (deviceName); + return NULL; + } + + struct drm_exynos_vidi_connection vidi; + + vidi.connection = 1; + vidi.extensions = 1; + vidi.edid = (uint64_t *)fake_edid_info; + + ioctl (drm_fd, DRM_IOCTL_EXYNOS_VIDI_CONNECTION, &vidi); + + if (deviceName) + Xfree (deviceName); + + /* get the drm magic */ + drmGetMagic (drm_fd, &magic); + fprintf (stderr, ">>> drm magic=%d \n", magic); + if (!DRI2Authenticate (dpy, RootWindow (dpy, screen), magic)) { + fprintf (stderr, "!!Error : DRI2Authenticate !!\n"); + close (drm_fd); + return NULL; + } + + // drm slp buffer manager init + bufmgr = tbm_bufmgr_init (drm_fd); + if (!bufmgr) { + GST_ERROR ("Error : fail to init buffer manager "); + close (drm_fd); + return NULL; + } + + DRI2CreateDrawable (dpy, pixmap); + return bufmgr; +} + +static int +port_get (GstXVImageSrc * src, unsigned int id) +{ + unsigned int ver, rev, req_base, err_base; + unsigned int adaptors; + XvAdaptorInfo *ai = NULL; + XvAttribute *at = NULL; + XvImageFormatValues *fo = NULL; + int attributes, formats; + int i, j, p; + + if (XvQueryExtension (src->dpy, &ver, &rev, &req_base, &src->evt_base, + &err_base) != Success) + return -1; + + if (XvQueryAdaptors (src->dpy, DefaultRootWindow (src->dpy), &adaptors, + &ai) != Success) + return -1; + + if (!ai) + return -1; + + for (i = 0; i < adaptors; i++) { + int support_format = False; + if (!(ai[i].type & XvInputMask) || !(ai[i].type & XvStillMask)) + continue; + + GST_LOG ("==========================================="); + GST_LOG (" name: %s" + " first port: %ld" + " ports: %ld", ai[i].name, ai[i].base_id, ai[i].num_ports); + p = ai[i].base_id; + GST_LOG (" attribute list:"); + at = XvQueryPortAttributes (src->dpy, p, &attributes); + for (j = 0; j < attributes; j++) + GST_LOG ("\t- name: %s\n" + "\t\t flags: %s%s\n" + "\t\t min_value: %i\n" + "\t\t max_value: %i\n", + at[j].name, + (at[j].flags & XvGettable) ? " get" : "", + (at[j].flags & XvSettable) ? " set" : "", + at[j].min_value, at[j].max_value); + + if (at) + XFree (at); + + GST_LOG (" image format list:"); + fo = XvListImageFormats (src->dpy, p, &formats); + for (j = 0; j < formats; j++) { + GST_LOG ("\t- 0x%x (%4.4s) %s", fo[j].id, (char *) &fo[j].id, + (fo[j].format == XvPacked) ? "packed" : "planar"); + if (fo[j].id == (int) id) + support_format = True; + } + + if (fo) + XFree (fo); + if (!support_format) + continue; + + for (; p < ai[i].base_id + ai[i].num_ports; p++) { + if (XvGrabPort (src->dpy, p, 0) == Success) { + GST_LOG ("========================================"); + GST_DEBUG ("XvGrabPort success : %d", p); + GST_LOG ("========================================"); + XvFreeAdaptorInfo (ai); + return p; + } + } + } + + GST_ERROR_OBJECT (src, "XvGrabPort failed"); + XvFreeAdaptorInfo (ai); + return -1; +} + +static void +pixmap_update (GstXVImageSrc * src, Display * dpy, tbm_bufmgr bufmgr, + Pixmap pixmap, int x, int y, int width, int height) +{ + unsigned int attachments[1]; + int dri2_count, dri2_out_count; + int dri2_width, dri2_height, dri2_stride; + int opt; + tbm_bo_handle temp_virtual; + + attachments[0] = DRI2BufferFrontLeft; + dri2_count = 1; + src->dri2_buffers = + DRI2GetBuffers (dpy, pixmap, &dri2_width, &dri2_height, attachments, + dri2_count, &dri2_out_count); + + if (!src->dri2_buffers) { + GST_ERROR ("[Error] : fail to get buffers"); + goto update_done; + } + + if (!src->dri2_buffers[0].name) { + GST_ERROR ("[Error] : a handle of the dri2 buffer is null "); + goto update_done; + } + + src->bo = tbm_bo_import (bufmgr, src->dri2_buffers[0].name); + if (!src->bo) { + GST_ERROR ("[Error] : cannot import bo (key:%d)", + src->dri2_buffers[0].name); + goto update_done; + } + + dri2_stride = src->dri2_buffers[0].pitch; + opt = TBM_OPTION_READ | TBM_OPTION_WRITE; + + temp_virtual = tbm_bo_map (src->bo, TBM_DEVICE_CPU, opt); + src->virtual = temp_virtual.ptr; + if (!src->virtual) { + GST_ERROR ("[Error] : fail to map "); + goto update_done; + } + + return; +update_done: + if (src->virtual) + tbm_bo_unmap (src->bo); + src->virtual = NULL; + + if (src->bo) + tbm_bo_unref (src->bo); + src->bo = NULL; + + if (src->dri2_buffers) + free (src->dri2_buffers); + src->dri2_buffers = NULL; + + return; +} + +static Pixmap +pixmap_create (GstXVImageSrc * src, Display * dpy, int width, int height) +{ + Pixmap pixmap = 0; + + pixmap = XCreatePixmap (dpy, DefaultRootWindow (dpy), width, height, + DefaultDepth (dpy, DefaultScreen (dpy))); + if (pixmap <= 0) { + GST_ERROR_OBJECT (src, "Failed to create pixmap"); + return 0; + } + + src->gc = XCreateGC (dpy, pixmap, 0, 0); + if (src->gc == NULL) { + GST_ERROR_OBJECT (src, "Failed to create GC"); + XFreePixmap (dpy, pixmap); + return 0; + } + + XSetForeground (dpy, src->gc, 0xFFFF0000); + XFillRectangle (dpy, pixmap, src->gc, 0, 0, width, height); + XSync (dpy, 0); + XFreeGC (dpy, src->gc); + + return pixmap; +} + +static gboolean +gst_xv_image_src_stop (GstBaseSrc * bsrc) +{ + GstXVImageSrc *src = GST_XV_IMAGE_SRC (bsrc); + GST_DEBUG_OBJECT (src, "stop()"); + + if (src->updates_thread) { + src->thread_return = TRUE; + g_thread_join (src->updates_thread); + src->updates_thread = NULL; + } + GST_DEBUG_OBJECT (src, "stop end "); + return TRUE; +} + +/* Interrupt a blocking request. */ +static gboolean +gst_xv_image_src_unlock (GstBaseSrc * bsrc) +{ + GstXVImageSrc *src = GST_XV_IMAGE_SRC (bsrc); + GST_DEBUG_OBJECT (src, "unlock()"); + return TRUE; +} + +/* Interrupt interrupt. */ +static gboolean +gst_xv_image_src_unlock_stop (GstBaseSrc * bsrc) +{ + GstXVImageSrc *src = GST_XV_IMAGE_SRC (bsrc); + GST_DEBUG_OBJECT (src, "unlock_stop()"); + return TRUE; +} + +static gboolean +gst_xv_image_src_get_size (GstBaseSrc * bsrc, guint64 * size) +{ + GstXVImageSrc *src = GST_XV_IMAGE_SRC (bsrc); + GST_INFO ("Get size %p", src); + return FALSE; +} + +static gboolean +gst_xv_image_src_is_seekable (GstBaseSrc * bsrc) +{ + GstXVImageSrc *src = GST_XV_IMAGE_SRC (bsrc); + GST_INFO_OBJECT (src, "Is seekable"); + return FALSE; +} + +static gboolean +gst_xv_image_src_query (GstBaseSrc * bsrc, GstQuery * query) +{ + GstXVImageSrc *src = GST_XV_IMAGE_SRC (bsrc); + gboolean ret; + + switch (GST_QUERY_TYPE (query)) { + default: + GST_INFO_OBJECT (src, "Default"); + break; + } + + ret = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query); + + return ret; +} + +static gboolean +plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (xvimagesrc_debug, "xvimagesrc", 0, + "XServer display FB video capture Source"); + return gst_element_register (plugin, "xvimagesrc", GST_RANK_PRIMARY, + GST_TYPE_XV_IMAGE_SRC); +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + xvimage, + "XServer display video src", + plugin_init, VERSION, "LGPL", "Samsung Electronics Co", + "http://www.samsung.com") diff --git a/xvimagesrc/src/gstxvimagesrc.h b/xvimagesrc/src/gstxvimagesrc.h new file mode 100644 index 0000000..e6b874b --- /dev/null +++ b/xvimagesrc/src/gstxvimagesrc.h @@ -0,0 +1,140 @@ +/* + * xvimagesrc + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyunil Park + * + * 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_XV_IMAGE_SRC_H__ +#define __GST_XV_IMAGE_SRC_H__ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include //libdri2-dev, libdrm-dev +#include + +#include "xv_types.h" + +#define C(b,m) (((b) >> (m)) & 0xFF) +#define B(c,s) ((((unsigned int)(c)) & 0xff) << (s)) +#define FOURCC(a,b,c,d) (B(d,24) | B(c,16) | B(b,8) | B(a,0)) +#define FOURCC_RGB32 FOURCC('R','G','B','4') +#define FOURCC_I420 FOURCC('I','4','2','0') +#define FOURCC_SN12 FOURCC('S','N','1','2') +#define FOURCC_ST12 FOURCC('S','T','1','2') + +G_BEGIN_DECLS +#define GST_TYPE_XV_IMAGE_SRC \ + (gst_xv_image_src_get_type()) +#define GST_XV_IMAGE_SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_XV_IMAGE_SRC,GstXVImageSrc)) +#define GST_XV_IMAGE_SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_TYPE_XV_IMAGE_SRC,GstXVImageSrcClass)) +#define GST_IS_XV_IMAGE_SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_XV_IMAGE_SRC)) +#define GST_IS_XV_IMAGE_SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_XV_IMAGE_SRC)) +typedef struct _GstXVImageSrc GstXVImageSrc; +typedef struct _GstXVImageSrcClass GstXVImageSrcClass; + +struct _GstXVImageSrc +{ + GstPushSrc element; + Display *dpy; + int p; + Pixmap pixmap; + GC gc; + unsigned int width; + unsigned int height; + unsigned int framesize; + guint32 format_id; + Damage damage; + int damage_base; + unsigned int evt_base; + tbm_bufmgr bufmgr; + void *virtual; + tbm_bo bo; + DRI2Buffer *dri2_buffers; + int buf_share_method; + guint64 running_time; + guint64 base_time; + guint64 frame_duration; + gint rate_numerator; + gint rate_denominator; + GThread *updates_thread; + gboolean thread_return; + GQueue *queue; + GMutex *queue_lock; + GCond *queue_cond; + GMutex *cond_lock; + GCond *buffer_cond; + GMutex *buffer_cond_lock; + GMutex *dpy_lock; + gint drm_fd; + int current_data_type; + int new_data_type; + double get_image_overtime; + int get_image_overtime_cnt; + int gemname_cnt; + int tz_enable; + long sleep_base_time; + long sleep_limit_time; + + /* For display selection */ + Window win; + Atom requestor; + Atom selection; + Atom target; + Atom property; +}; + +struct _GstXVImageSrcClass +{ + GstPushSrcClass parent_class; + + /* signals */ + void (*video_with_ui) (void *data); + void (*video_only) (void *data); + void (*selection_notify) (void *data); +}; + +GType gst_xv_image_src_get_type (void); + +G_END_DECLS +#endif /* __GST_XV_IMAGE_SRC_H__ */ diff --git a/xvimagesrc/src/xv_types.h b/xvimagesrc/src/xv_types.h new file mode 100644 index 0000000..4afa687 --- /dev/null +++ b/xvimagesrc/src/xv_types.h @@ -0,0 +1,169 @@ +/************************************************************************** + +xserver-xorg-video-exynos + +Copyright 2010 - 2011 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: Boram Park + +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, sub license, 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 (including the +next paragraph) 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 NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + +**************************************************************************/ + +/* */ +/* File name : xv_types.h */ +/* Author : Boram Park (boram1288.park@samsung.com) */ +/* Protocol Version : 1.0.1 (Dec 16th 2009) */ +/* This file is for describing Xv APIs' buffer encoding method. */ +/* */ + +#ifndef __XV_TYPE_H__ +#define __XV_TYPE_H__ + +#define XV_DATA_HEADER 0xDEADCD01 +#define XV_DATA_VERSION 0x00010001 + +/* Return Values */ +#define XV_OK 0 +#define XV_HEADER_ERROR -1 +#define XV_VERSION_MISMATCH -2 + +/* Video Mode */ +#define DISPLAY_MODE_DEFAULT 0 +#define DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_FULL_SCREEN 1 +#define DISPLAY_MODE_PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN 2 + +/* Color space range */ +#define CSC_RANGE_NARROW 0 +#define CSC_RANGE_WIDE 1 + +/* Buffer Type */ +#define XV_BUF_TYPE_DMABUF 0 +#define XV_BUF_TYPE_LEGACY 1 +#define XV_BUF_PLANE_NUM 3 + +/* Data structure for XvPutImage / XvShmPutImage */ +typedef struct +{ + unsigned int _header; /* for internal use only */ + unsigned int _version; /* for internal use only */ + + unsigned int YBuf; + unsigned int CbBuf; + unsigned int CrBuf; + unsigned int BufType; + unsigned int dmabuf_fd[XV_BUF_PLANE_NUM]; + unsigned int gem_handle[XV_BUF_PLANE_NUM]; + void *bo[XV_BUF_PLANE_NUM]; +} XV_DATA, * XV_DATA_PTR; + +static void +#ifdef __GNUC__ +__attribute__ ((unused)) +#endif +XV_INIT_DATA (XV_DATA_PTR data) +{ + data->_header = XV_DATA_HEADER; + data->_version = XV_DATA_VERSION; +} + +static int +#ifdef __GNUC__ +__attribute__ ((unused)) +#endif +XV_VALIDATE_DATA (XV_DATA_PTR data) +{ + if (data->_header != XV_DATA_HEADER) + return XV_HEADER_ERROR; + if (data->_version != XV_DATA_VERSION) + return XV_VERSION_MISMATCH; + return XV_OK; +} + +/* max channel count *********************************************************/ +#define SCMN_IMGB_MAX_PLANE (4) + +/* image buffer definition *************************************************** + + +------------------------------------------+ --- + | | ^ + | a[], p[] | | + | +---------------------------+ --- | | + | | | ^ | | + | |<---------- w[] ---------->| | | | + | | | | | | + | | | | + | | | h[] | e[] + | | | | + | | | | | | + | | | | | | + | | | v | | + | +---------------------------+ --- | | + | | v + +------------------------------------------+ --- + + |<----------------- s[] ------------------>| +*/ + +typedef struct +{ + /* width of each image plane */ + int w[SCMN_IMGB_MAX_PLANE]; + /* height of each image plane */ + int h[SCMN_IMGB_MAX_PLANE]; + /* stride of each image plane */ + int s[SCMN_IMGB_MAX_PLANE]; + /* elevation of each image plane */ + int e[SCMN_IMGB_MAX_PLANE]; + /* user space address of each image plane */ + void *a[SCMN_IMGB_MAX_PLANE]; + /* physical address of each image plane, if needs */ + void *p[SCMN_IMGB_MAX_PLANE]; + /* color space type of image */ + int cs; + /* left postion, if needs */ + int x; + /* top position, if needs */ + int y; + /* to align memory */ + int __dummy2; + /* arbitrary data */ + int data[16]; + /* dma buf fd */ + int dmabuf_fd[SCMN_IMGB_MAX_PLANE]; + /* buffer share method */ + int buf_share_method; + /* Y plane size in case of ST12 */ + int y_size; + /* UV plane size in case of ST12 */ + int uv_size; + /* Tizen buffer object */ + void *bo[SCMN_IMGB_MAX_PLANE]; + /* JPEG data */ + void *jpeg_data; + /* JPEG size */ + int jpeg_size; + /* TZ memory buffer */ + int tz_enable; +} SCMN_IMGB; + +#endif + -- 2.7.4