Most of the code are cloned from gst-nokia-videosrc.
Made little changes to the v4l2newcamsrc to support basic image/video capture
for Intel Medfield platform camera.
--- /dev/null
+INSTALL
+Makefile
+Makefile.in
+aclocal.m4
+autom4te.cache
+autoregen.sh
+compile
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+configure
+depcomp
+gtk-doc.make
+install-sh
+libtool
+ltmain.sh
+missing
+gstreamer-nokia-videosrc*.pc
+stamp-h1
+
+.deps
+.libs
+*.lo
+*.la
+*.o
+*~
+/m4
+Makefile.in
+Makefile
+cscope*
--- /dev/null
+Nokia Corporation <multimedia@maemo.org>
--- /dev/null
+ 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.
+\f
+ 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.
+\f
+ 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.
+\f
+ 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.
+\f
+ 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.
+\f
+ 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.
+\f
+ 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.
+\f
+ 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.
+\f
+ 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
+\f
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
--- /dev/null
+DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc
+
+SUBDIRS = m4 gst-libs gst docs pkgconfig
--- /dev/null
+Nothing much yet.
--- /dev/null
+This is Medfield Camera Source element baseed on gst-nokia-videosrc.
--- /dev/null
+#!/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
+
+DIE=0
+package=gst-nokia-videosrc
+
+# autogen.sh helper functions (copied from GStreamer's common/ CVS module)
+if test ! -f ./gst-autogen.sh;
+then
+ echo There is something wrong with your source tree.
+ echo You are either missing ./gst-autogen.sh or not
+ echo running autogen.sh from the top-level source
+ echo directory.
+ exit 1
+fi
+. ./gst-autogen.sh
+
+CONFIGURE_DEF_OPT='--enable-maintainer-mode --enable-debug --enable-gtk-doc'
+
+autogen_options $@
+
+echo -n "+ check for build tools"
+if test ! -z "$NOCHECK"; then echo " skipped"; else echo; fi
+version_check "autoconf" "$AUTOCONF autoconf autoconf259 autoconf257 autoconf-2.54 autoconf-2.53 autoconf-2.52" \
+ "ftp://ftp.gnu.org/pub/gnu/autoconf/" 2 52 || DIE=1
+version_check "automake" "$AUTOMAKE automake automake-1.9 automake19 automake-1.7 automake-1.6 automake-1.5" \
+ "ftp://ftp.gnu.org/pub/gnu/automake/" 1 7 || DIE=1
+###version_check "autopoint" "autopoint" \
+### "ftp://ftp.gnu.org/pub/gnu/gettext/" 0 11 5 || DIE=1
+version_check "libtoolize" "$LIBTOOLIZE libtoolize glibtoolize" \
+ "ftp://ftp.gnu.org/pub/gnu/libtool/" 1 5 0 || DIE=1
+version_check "pkg-config" "" \
+ "http://www.freedesktop.org/software/pkgconfig" 0 8 0 || DIE=1
+
+have_gtkdoc_1_9=0
+version_check "gtkdocize" "" "" 1 9 && have_gtkdoc_1_9=1
+if test "x$have_gtkdoc_1_9" = "x0"; then
+version_check "gtkdocize" "" \
+ "ftp://ftp.gnome.org/pub/gnome/sources/gtk-doc/" 1 4
+fi
+
+die_check $DIE
+
+autoconf_2_52d_check || DIE=1
+aclocal_check || DIE=1
+autoheader_check || DIE=1
+
+die_check $DIE
+
+# if no arguments specified then this will be printed
+if test -z "$*"; then
+ echo "+ checking for autogen.sh options"
+ echo " This autogen script will automatically run ./configure as:"
+ echo " ./configure $CONFIGURE_DEF_OPT"
+ echo " To pass any additional options, please specify them on the $0"
+ echo " command line."
+fi
+
+tool_run "$aclocal" "-I m4/ $ACLOCAL_FLAGS"
+tool_run "$libtoolize" "--copy --force"
+if test -n "$gtkdocize"; then
+ if test "x$have_gtkdoc_1_9" = "x0"; then
+ tool_run "$gtkdocize" "--copy"
+ else
+ tool_run "$gtkdocize" "--copy --flavour no-tmpl"
+ fi
+else
+ echo "EXTRA_DIST = " > gtk-doc.make
+fi
+tool_run "$autoheader"
+tool_run "$autoconf"
+tool_run "$automake" "-a -c"
+
+# if enable exists, add an -enable option for each of the lines in that file
+if test -f enable; then
+ for a in `cat enable`; do
+ CONFIGURE_FILE_OPT="--enable-$a"
+ done
+fi
+
+# if disable exists, add an -disable option for each of the lines in that file
+if test -f disable; then
+ for a in `cat disable`; do
+ CONFIGURE_FILE_OPT="$CONFIGURE_FILE_OPT --disable-$a"
+ done
+fi
+
+test -n "$NOCONFIGURE" && {
+ echo "+ skipping configure stage for package $package, as requested."
+ echo "+ autogen.sh done."
+ exit 0
+}
+
+echo "+ running configure ... "
+test ! -z "$CONFIGURE_DEF_OPT" && echo " ./configure default flags: $CONFIGURE_DEF_OPT"
+test ! -z "$CONFIGURE_EXT_OPT" && echo " ./configure external flags: $CONFIGURE_EXT_OPT"
+test ! -z "$CONFIGURE_FILE_OPT" && echo " ./configure enable/disable flags: $CONFIGURE_FILE_OPT"
+echo
+
+./configure $CONFIGURE_DEF_OPT $CONFIGURE_EXT_OPT $CONFIGURE_FILE_OPT || {
+ echo " configure failed"
+ exit 1
+}
+
+echo "Now type 'make' to compile $package."
--- /dev/null
+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"
+
--- /dev/null
+AC_INIT
+
+dnl versions of gstreamer and plugins-base
+GST_MAJORMINOR=0.10
+GST_REQUIRED=0.10.0
+GSTPB_REQUIRED=0.10.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-plugins-camera, GST_PLUGIN_VERSION, 0, 10, 0, 0,
+ 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)
+
+dnl make aclocal work in maintainer mode
+AC_SUBST(ACLOCAL_AMFLAGS, "-I m4")
+AC_CONFIG_MACRO_DIR(m4)
+
+AM_CONFIG_HEADER(config.h)
+
+dnl check for tools
+AC_PROG_CC
+AC_PROG_LIBTOOL
+
+# check for gtk-doc
+GTK_DOC_CHECK(1.6)
+
+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
+
+
+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
+AC_SUBST(GST_CFLAGS)
+AC_SUBST(GST_LIBS)
+
+dnl make GST_MAJORMINOR available in Makefile.am
+AC_SUBST(GST_MAJORMINOR)
+
+AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug], [compile with DEBUG]),,enable_debug=no)
+
+DEBUG_FLAGS=
+dnl Check for debug build
+if test "x$enable_debug" = "xyes"; then
+ DEBUG_FLAGS="-DDEBUG"
+fi
+
+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 Check gst-plugins-bad
+PKG_CHECK_MODULES(GST_BAD, gstreamer-plugins-bad-$GST_MAJORMINOR,
+ HAVE_GST_BAD=yes, HAVE_GST_BAD=no)
+
+if test "x$HAVE_GST_BAD" = "xno"; then
+ AC_MSG_NOTICE(no gstreamer-plugins-bad libraries found (gstreamer-plugins-bad-$GST_MAJORMINOR))
+fi
+
+dnl make _CFLAGS and _LIBS available
+AC_SUBST(GST_BAD_CFLAGS)
+AC_SUBST(GST_BAD_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_\).*'
+AC_SUBST(GST_PLUGIN_LDFLAGS)
+
+dnl LDFLAGS really should only contain flags, not libs - they get added before
+dnl whatevertarget_LIBS and -L flags here affect the rest of the linking
+GST_ALL_LDFLAGS="-no-undefined"
+AC_SUBST(GST_ALL_LDFLAGS)
+
+dnl GST_LIB_LDFLAGS
+dnl linker flags shared by all libraries
+dnl LDFLAGS modifier defining exported symbols from built libraries
+dnl (export _gst_foo but not __gst_foo)
+GST_LIB_LDFLAGS="-export-symbols-regex ^_?\(gst_\|Gst\|GST_\).*"
+AC_SUBST(GST_LIB_LDFLAGS)
+
+dnl check gst check support
+HAVE_GST_CHECK=no
+PKG_CHECK_MODULES(GST_CHECK, gstreamer-check-$GST_MAJORMINOR, HAVE_GST_CHECK=yes, HAVE_GST_CHECK=no)
+AM_CONDITIONAL(HAVE_GST_CHECK, test "x$HAVE_GST_CHECK" = "xyes")
+AC_SUBST(GST_CHECK_CFLAGS)
+AC_SUBST(GST_CHECK_LIBS)
+
+
+AC_PATH_PROG(VALGRIND_PATH, valgrind, no)
+AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno")
+
+GST_PLUGINS_DIR=`$PKG_CONFIG --variable=pluginsdir gstreamer-$GST_MAJORMINOR`
+AC_MSG_NOTICE([using GStreamer plug-ins in $GST_PLUGINS_DIR])
+AC_SUBST(GST_PLUGINS_DIR)
+
+GENERAL_CFLAGS="-D___LINUX___ -D___GNUC___ -DOSAL_ROVER $DEBUG_FLAGS"
+AC_SUBST(GENERAL_CFLAGS)
+
+AC_OUTPUT(Makefile \
+ m4/Makefile \
+ gst-libs/Makefile \
+ gst-libs/gst/Makefile \
+ gst-libs/gst/camera/Makefile \
+ gst/Makefile \
+ gst/v4l2newcam/Makefile \
+ docs/Makefile \
+ docs/reference/Makefile \
+ docs/reference/gst-nokia-videosrc/Makefile
+ pkgconfig/Makefile
+ pkgconfig/gstreamer-nokia-videosrc.pc)
--- /dev/null
+if ENABLE_GTK_DOC
+GTK_DOC_DIRS = reference
+else
+GTK_DOC_DIRS =
+endif
+
+SUBDIRS = $(GTK_DOC_DIRS)
--- /dev/null
+SUBDIRS = gst-nokia-videosrc
--- /dev/null
+## Process this file with automake to produce Makefile.in
+
+# We require automake 1.6 at least.
+AUTOMAKE_OPTIONS = 1.6
+
+SUBDIRS=.
+
+# The name of the module, e.g. 'glib'.
+DOC_MODULE=gst-nokia-videosrc
+
+# The top-level SGML file. You can change this if you want to.
+DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
+
+# The directory containing the source code. Relative to $(srcdir).
+# gtk-doc will search all .c & .h files beneath here for inline comments
+# documenting the functions and macros.
+# e.g. DOC_SOURCE_DIR=../../../gtk
+DOC_SOURCE_DIR = $(top_srcdir)
+
+# Extra options to pass to gtkdoc-scangobj. Not normally needed.
+SCANGOBJ_OPTIONS=--type-init-func="g_type_init();gst_init(&argc,&argv)"
+
+# Extra options to supply to gtkdoc-scan.
+# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
+SCAN_OPTIONS=
+
+# Extra options to supply to gtkdoc-mkdb.
+# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml
+MKDB_OPTIONS=--sgml-mode --output-format=xml
+
+# Extra options to supply to gtkdoc-mktmpl
+# e.g. MKTMPL_OPTIONS=--only-section-tmpl
+MKTMPL_OPTIONS=
+
+# Extra options to supply to gtkdoc-fixref. Not normally needed.
+# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
+FIXXREF_OPTIONS=
+
+# Used for dependencies. The docs will be rebuilt if any of these change.
+# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
+# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
+#HFILE_GLOB=$(top_srcdir)/gst-libs/gst/camera/*.h
+#CFILE_GLOB=$(top_srcdir)/gst-libs/gst/camera/*.c
+
+HFILE_GLOB=$(DOC_SOURCE_DIR)/*/*/*.h
+CFILE_GLOB=$(DOC_SOURCE_DIR)/*/*/*.c
+
+SCANOBJ_DEPS = \
+ $(top_builddir)/gst-libs/gst/camera/libgstcamera-@GST_MAJORMINOR@.la
+
+# Header files to ignore when scanning.
+# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
+IGNORE_HFILES=config.h
+
+# Images to copy into HTML directory.
+# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
+HTML_IMAGES=
+
+# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
+# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
+content_files=
+
+# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
+# These files must be listed here *and* in content_files
+# e.g. expand_content_files=running.sgml
+expand_content_files=
+
+# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
+# Only needed if you are using gtkdoc-scangobj to dynamically query widget
+# signals and properties.
+# e.g. INCLUDES=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
+# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
+GTKDOC_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) \
+ -I$(top_srcdir)/gst-libs/gst/camera
+
+GTKDOC_LIBS=$(GST_LIBS) $(GST_BASE_LIBS) $(SCANOBJ_DEPS) \
+ -lgstinterfaces-$(GST_MAJORMINOR) \
+ -lgstphotography-$(GST_MAJORMINOR)
+
+# This includes the standard gtk-doc make rules, copied by gtkdocize.
+include $(top_srcdir)/gtk-doc.make
+
+# Other files to distribute
+# e.g. EXTRA_DIST += version.xml.in
+EXTRA_DIST +=
+
+# Files not to distribute
+# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
+# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
+#DISTCLEANFILES +=
+
+# Comment this out if you want your docs-status tested during 'make check'
+#TESTS = $(GTKDOC_CHECK)
+
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">
+<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
+ <bookinfo>
+ <title>gstreamer0.10-nokia-videosrc Reference Manual</title>
+ <releaseinfo>
+ for gstreamer-nokia-videosrc 0.10
+ <!--The latest version of this documentation can be found on-line at
+ <ulink role="online-location" url="http://[SERVER]/gstreamer0.10-nokia-videosrc/index.html">http://[SERVER]/gstreamer0.10-nokia-videosrc/</ulink>.
+ -->
+ </releaseinfo>
+ </bookinfo>
+
+ <chapter>
+ <title>GStreamer Camera Source base class public API</title>
+ <xi:include href="xml/gstcamerasrc.xml"/>
+ <xi:include href="xml/gstcameracolorbalance.xml"/>
+ <xi:include href="xml/gstcameraphotoiface.xml"/>
+ </chapter>
+
+ <chapter>
+ <title>SubdevSrc element</title>
+ <xi:include href="xml/element-subdevsrc.xml"/>
+ <xi:include href="xml/bufferpool.xml"/>
+ <xi:include href="xml/recyclepool.xml"/>
+ <xi:include href="xml/subdev_calls.xml"/>
+ <xi:include href="xml/libomap3camd_calls.xml"/>
+ <xi:include href="xml/mediacontroller.xml"/>
+ </chapter>
+
+ <chapter>
+ <title>New V4L2camsrc element</title>
+ <xi:include href="xml/element-v4l2newcamsrc.xml"/>
+ <xi:include href="xml/v4l2camsrc_calls.xml"/>
+ </chapter>
+
+ <chapter id="objecttree">
+ <title>Object Hierarchy</title>
+ <xi:include href="xml/tree_index.sgml"/>
+ </chapter>
+
+ <index id="api-index">
+ <title>API Index</title>
+ </index>
+</book>
--- /dev/null
+<SECTION>
+<FILE>gstcamerasrc</FILE>
+<TITLE>GstCameraSrc base class</TITLE>
+<INCLUDE>gst-libs/gst/camera/gstcamerasrc.h</INCLUDE>
+GstCameraSrc
+GstCameraSrcClass
+GstCameraSrcCaptureMode
+GstCameraSrcViewfinderMode
+GstCameraSrcAFReqMode
+GstCameraCapturePhase
+gst_camerasrc_add_color_channel
+gst_camerasrc_clear_color_channels
+gst_camerasrc_send_capture_start_message
+gst_camerasrc_send_capture_stop_message
+gst_camerasrc_get_caps_from_info
+GST_CAMERA_SRC_MAX_SIZE
+<SUBSECTION Standard>
+GST_TYPE_CAMERA_SRC
+GST_CAMERA_SRC
+GST_CAMERA_SRC_CLASS
+GST_CAMERA_SRC_GET_CLASS
+GST_IS_CAMERA_SRC
+GST_IS_CAMERA_SRC_CLASS
+GST_CAMERA_SRC_CAST
+GST_CAMERA_SRC_CLASS_CAST
+GST_TYPE_CAMERA_SRC_CAPTURE_MODE
+GST_TYPE_CAMERA_SRC_VIEWFINDER_MODE
+gst_camerasrc_get_type
+</SECTION>
+
+<SECTION>
+<FILE>gstcameracolorbalance</FILE>
+<TITLE>GstColorBalanceChannel interface implementation</TITLE>
+GstCameraSrcColorBalanceChannel
+GstCameraSrcColorBalanceChannelClass
+gst_camerasrc_color_balance_list_channels
+gst_camerasrc_color_balance_set_value
+gst_camerasrc_color_balance_get_value
+GST_IMPLEMENT_CAMERA_SRC_COLOR_BALANCE_METHODS
+<SUBSECTION Standard>
+GST_CAMERA_SRC_COLOR_BALANCE_CHANNEL
+GST_IS_CAMERA_SRC_COLOR_BALANCE_CHANNEL
+GST_TYPE_CAMERA_SRC_COLOR_BALANCE_CHANNEL
+gst_camerasrc_color_balance_channel_get_type
+GST_CAMERA_SRC_COLOR_BALANCE_CHANNEL_CLASS
+GST_IS_CAMERA_SRC_COLOR_BALANCE_CHANNEL_CLASS
+</SECTION>
+
+<SECTION>
+<FILE>gstcameraphotoiface</FILE>
+<TITLE>GstPhotography interface implementation</TITLE>
+gst_camerasrc_photo_set_ev_compensation
+gst_camerasrc_photo_get_ev_compensation
+gst_camerasrc_photo_set_iso_speed
+gst_camerasrc_photo_get_iso_speed
+gst_camerasrc_photo_set_aperture
+gst_camerasrc_photo_get_aperture
+gst_camerasrc_photo_set_exposure
+gst_camerasrc_photo_get_exposure
+gst_camerasrc_photo_set_wb_mode
+gst_camerasrc_photo_get_wb_mode
+gst_camerasrc_photo_set_tone_mode
+gst_camerasrc_photo_get_tone_mode
+gst_camerasrc_photo_set_scene_mode
+gst_camerasrc_photo_get_scene_mode
+gst_camerasrc_photo_set_flash_mode
+gst_camerasrc_photo_get_flash_mode
+gst_camerasrc_photo_set_zoom
+gst_camerasrc_photo_get_zoom
+gst_camerasrc_photo_set_flicker_mode
+gst_camerasrc_photo_get_flicker_mode
+gst_camerasrc_photo_set_focus_mode
+gst_camerasrc_photo_get_focus_mode
+gst_camerasrc_photo_set_autofocus
+gst_camerasrc_photo_get_capabilities
+gst_camerasrc_photo_prepare_for_capture
+gst_camerasrc_photo_ready_for_capture
+gst_camerasrc_photo_set_config
+gst_camerasrc_photo_get_config
+gst_camerasrc_photo_set_format
+gst_camerasrc_photo_get_format
+gst_camerasrc_photo_set_property
+gst_camerasrc_photo_get_property
+GST_CAMERA_SRC_PHOTO_FUNCS
+GST_IMPLEMENT_CAMERA_SRC_PHOTO_METHODS
+</SECTION>
+
+<SECTION>
+<FILE>element-subdevsrc</FILE>
+<TITLE>Subdevsrc element</TITLE>
+GstSubdevSrc
+GstSubdevSrcClass
+GstVideoMode
+GstVideoFrameInfo
+GstSubdevSrcCameraDevice
+MAX_HQ_BUFFERS
+MAX_PRV_BUFFERS
+MAX_RESIZER_FACTOR
+gst_subdevsrc_send_makernote
+gst_subdevsrc_send_postproc_params
+gst_subdevsrc_get_shake_risk
+<SUBSECTION Standard>
+GST_SUBDEVSRC
+GST_SUBDEVSRC_CLASS
+GST_IS_SUBDEVSRC
+GST_IS_SUBDEVSRC_CLASS
+GST_TYPE_SUBDEVSRC
+GST_TYPE_SUBDEVSRC_CAMERA_DEVICE
+gst_subdevsrc_get_type
+gst_subdevsrc_camera_device_get_type
+</SECTION>
+
+<SECTION>
+<FILE>subdev_calls</FILE>
+<TITLE>Subdev device calls</TITLE>
+GST_SUBDEVSRC_MIN_BUFFERS
+GST_SUBDEVSRC_MAX_BUFFERS
+GST_SUBDEVSRC_DEFAULT_BUFFERS
+gst_subdevsrc_open
+gst_subdevsrc_close
+gst_subdevsrc_get_attribute
+gst_subdevsrc_set_attribute
+gst_subdevsrc_start
+gst_subdevsrc_grab_frame
+gst_subdevsrc_stop
+gst_subdevsrc_get_max_zoom
+gst_subdevsrc_fill_format_list
+gst_subdevsrc_probe_caps
+gst_subdevsrc_set_zoom
+</SECTION>
+
+<SECTION>
+<FILE>libomap3camd_calls</FILE>
+<TITLE>Calls to libomap3camd API</TITLE>
+gst_subdevsrc_libomap3camd_class_init
+gst_subdevsrc_libomap3camd_init
+gst_subdevsrc_libomap3camd_deinit
+gst_subdevsrc_libomap3camd_set_privacy_light
+gst_subdevsrc_libomap3camd_daemon_start
+gst_subdevsrc_libomap3camd_daemon_stop
+gst_subdevsrc_libomap3camd_grab_hq_frame
+gst_subdevsrc_libomap3camd_get_makernote
+gst_subdevsrc_libomap3camd_get_pp_params
+gst_subdevsrc_libomap3camd_check_shaking
+gst_subdevsrc_libomap3camd_handle_motion_event
+gst_subdevsrc_libomap3camd_handle_roi_event
+gst_subdevsrc_libomap3camd_set_capture_fmt
+gst_subdevsrc_libomap3camd_set_preview_fmt
+gst_subdevsrc_libomap3camd_set_zoom
+</SECTION>
+
+<SECTION>
+<FILE>mediacontroller</FILE>
+<TITLE>Media Controller calls</TITLE>
+GstMediaController
+GstMediaEntity
+gst_subdevsrc_mc_init
+gst_subdevsrc_mc_deinit
+gst_subdevsrc_mc_get_device_fd
+gst_subdevsrc_mc_setup_pipeline
+gst_subdevsrc_mc_reset_links
+</SECTION>
+
+<SECTION>
+<FILE>bufferpool</FILE>
+<TITLE>Video buffer pool</TITLE>
+GstSubdevBuffer
+GstSubdevSrcBufferPool
+gst_subdevsrc_buffer_pool_new
+gst_subdevsrc_buffer_pool_destroy
+gst_subdevsrc_buffer_pool_activate
+gst_subdevsrc_buffer_pool_update
+<SUBSECTION Standard>
+GST_SUBDEVSRC_BUFFER
+GST_IS_SUBDEVSRC_BUFFER
+GST_TYPE_SUBDEVSRC_BUFFER
+gst_subdevsrc_buffer_get_type
+</SECTION>
+
+<SECTION>
+<FILE>recyclepool</FILE>
+<TITLE>Buffer recycling pool</TITLE>
+GstRecycleBuffer
+GstRecyclePool
+GstRecyclePoolClass
+AllocFunc
+RecycleFunc
+FreeFunc
+gst_recycle_pool_cleanup
+gst_recycle_pool_convert_buffer
+gst_recycle_pool_destroy
+gst_recycle_pool_free_buffer
+gst_recycle_pool_get_buffer
+gst_recycle_pool_new
+gst_recycle_pool_set_alloc_func
+gst_recycle_pool_set_free_func
+gst_recycle_pool_set_recycle_func
+</SECTION>
+
+<SECTION>
+<FILE>element-v4l2newcamsrc</FILE>
+<TITLE>New v4l2camsrc element</TITLE>
+GstV4l2NewCamSrc
+GstV4l2NewCamSrcClass
+</SECTION>
+
+<SECTION>
+<FILE>v4l2camsrc_calls</FILE>
+<TITLE>V4l2NewCamSrc V4L2 API calls</TITLE>
+GstV4l2Buffer
+GstV4l2NewCamSrcBufferPool
+</SECTION>
--- /dev/null
+#include <gst/gst.h>
+#include "gstcamerasrc.h"
+#include "gstcameracolorbalance.h"
+
+gst_camerasrc_get_type
+gst_camerasrc_color_balance_channel_get_type
--- /dev/null
+# 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
+ }
+}
--- /dev/null
+SUBDIRS = gst
--- /dev/null
+SUBDIRS = camera
+DIST_SUBDIRS = camera
--- /dev/null
+lib_LTLIBRARIES = libgstcamera-@GST_MAJORMINOR@.la
+
+libgstcamera_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/camera
+
+libgstcamera_@GST_MAJORMINOR@_la_SOURCES = gstcamerasrc.c \
+ gstcameracolorbalance.c \
+ gstcameraphotoiface.c
+
+libgstcamera_@GST_MAJORMINOR@include_HEADERS = gstcamerasrc.h \
+ gstcameracolorbalance.h
+
+libgstcamera_@GST_MAJORMINOR@_la_CFLAGS = $(GST_CFLAGS) -DGST_USE_UNSTABLE_API \
+ $(GST_PLUGINS_BASE_CFLAGS)
+
+libgstcamera_@GST_MAJORMINOR@_la_LIBADD = $(GST_LIBS) \
+ $(GST_BASE_LIBS) \
+ -lgstinterfaces-$(GST_MAJORMINOR) \
+ -lgsttag-$(GST_MAJORMINOR) \
+ -lgstphotography-$(GST_MAJORMINOR)
+
+libgstcamera_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) \
+ $(GST_ALL_LDFLAGS) \
+ $(GST_LT_LDFLAGS)
+
+noinst_HEADERS = gstcameraphotoiface.h
--- /dev/null
+/* GStreamer
+ *
+ * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * 2006 Edgard Lima <edgard.lima@indt.org.br>
+ * 2008-2010 Nokia Corporation <multimedia@maemo.org>
+ *
+ * gstcameracolorbalance.c: generic color balance interface implementation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include "gstcameracolorbalance.h"
+
+GST_BOILERPLATE (GstCameraSrcColorBalanceChannel,
+ gst_camerasrc_color_balance_channel,
+ GstColorBalanceChannel, GST_TYPE_COLOR_BALANCE_CHANNEL);
+
+static void
+gst_camerasrc_color_balance_channel_base_init (gpointer g_class)
+{
+}
+
+static void
+gst_camerasrc_color_balance_channel_class_init (GstCameraSrcColorBalanceChannelClass *
+ klass)
+{
+}
+
+static void
+gst_camerasrc_color_balance_channel_init (GstCameraSrcColorBalanceChannel * channel,
+ GstCameraSrcColorBalanceChannelClass * klass)
+{
+ channel->id = (guint32) - 1;
+}
+
+static G_GNUC_UNUSED gboolean
+gst_camerasrc_color_balance_contains_channel (GstCameraSrc * camerasrc,
+ GstCameraSrcColorBalanceChannel * channel)
+{
+ const GList *item;
+
+ for (item = camerasrc->colors; item != NULL; item = item->next)
+ if (item->data == channel)
+ return TRUE;
+
+ return FALSE;
+}
+
+const GList *
+gst_camerasrc_color_balance_list_channels (GstCameraSrc * camerasrc)
+{
+ return camerasrc->colors;
+}
+
+void
+gst_camerasrc_color_balance_set_value (GstCameraSrc * camerasrc,
+ GstColorBalanceChannel * channel, gint value)
+{
+ GstCameraSrcClass *bclass;
+ gboolean opened;
+
+ GstCameraSrcColorBalanceChannel *camchannel =
+ GST_CAMERA_SRC_COLOR_BALANCE_CHANNEL (channel);
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+ opened = bclass->is_open (camerasrc);
+
+ /* assert that we're opened and that we're using a known item */
+ g_return_if_fail (opened);
+ g_return_if_fail (gst_camerasrc_color_balance_contains_channel (camerasrc,
+ camchannel));
+
+ bclass->set_attribute (camerasrc, camchannel->id, value);
+}
+
+gint
+gst_camerasrc_color_balance_get_value (GstCameraSrc * camerasrc,
+ GstColorBalanceChannel * channel)
+{
+ GstCameraSrcClass *bclass;
+ gboolean opened;
+
+ GstCameraSrcColorBalanceChannel *camchannel =
+ GST_CAMERA_SRC_COLOR_BALANCE_CHANNEL (channel);
+ gint value;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+ opened = bclass->is_open (camerasrc);
+
+ /* assert that we're opened and that we're using a known item */
+ g_return_val_if_fail (opened, 0);
+ g_return_val_if_fail (gst_camerasrc_color_balance_contains_channel (camerasrc,
+ camchannel), 0);
+
+ if (!bclass->get_attribute (camerasrc, camchannel->id, &value))
+ return 0;
+
+ return value;
+}
--- /dev/null
+/* GStreamer
+ *
+ * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * 2006 Edgard Lima <edgard.lima@indt.org.br>
+ * 2008 Nokia Corporation <multimedia@maemo.org>
+ *
+ * gstcameracolorbalance.h: Generic color balance interface implementation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_CAMERA_SRC_COLOR_BALANCE_H__
+#define __GST_CAMERA_SRC_COLOR_BALANCE_H__
+
+#include <gst/gst.h>
+#include <gst/interfaces/colorbalance.h>
+
+#include "gstcamerasrc.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_CAMERA_SRC_COLOR_BALANCE_CHANNEL \
+ (gst_camerasrc_color_balance_channel_get_type ())
+#define GST_CAMERA_SRC_COLOR_BALANCE_CHANNEL(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CAMERA_SRC_COLOR_BALANCE_CHANNEL, \
+ GstCameraSrcColorBalanceChannel))
+#define GST_CAMERA_SRC_COLOR_BALANCE_CHANNEL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CAMERA_SRC_COLOR_BALANCE_CHANNEL, \
+ GstCameraSrcColorBalanceChannelClass))
+#define GST_IS_CAMERA_SRC_COLOR_BALANCE_CHANNEL(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CAMERA_SRC_COLOR_BALANCE_CHANNEL))
+#define GST_IS_CAMERA_SRC_COLOR_BALANCE_CHANNEL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CAMERA_SRC_COLOR_BALANCE_CHANNEL))
+
+typedef struct _GstCameraSrcColorBalanceChannel {
+ GstColorBalanceChannel parent;
+
+ guint32 id;
+} GstCameraSrcColorBalanceChannel;
+
+/**
+ * GstCameraSrcColorBalanceChannelClass:
+ * @parent: Element parent class
+ *
+ * #GstCameraSrcColorBalanceChannelClass class object.
+ */
+typedef struct _GstCameraSrcColorBalanceChannelClass {
+ GstColorBalanceChannelClass parent;
+} GstCameraSrcColorBalanceChannelClass;
+
+GType gst_camerasrc_color_balance_channel_get_type (void);
+
+const GList * gst_camerasrc_color_balance_list_channels (GstCameraSrc * camerasrc);
+
+void gst_camerasrc_color_balance_set_value (GstCameraSrc * camerasrc,
+ GstColorBalanceChannel * channel,
+ gint value);
+
+gint gst_camerasrc_color_balance_get_value (GstCameraSrc * camerasrc,
+ GstColorBalanceChannel * channel);
+
+#define GST_IMPLEMENT_CAMERA_SRC_COLOR_BALANCE_METHODS(Type, interface_as_function) \
+ \
+static const GList * \
+interface_as_function ## _color_balance_list_channels (GstColorBalance * balance) \
+{ \
+ Type *this = (Type*) balance; \
+ return gst_camerasrc_color_balance_list_channels(this); \
+} \
+ \
+static void \
+interface_as_function ## _color_balance_set_value (GstColorBalance * balance, \
+ GstColorBalanceChannel * channel, \
+ gint value) \
+{ \
+ Type *this = (Type*) balance; \
+ gst_camerasrc_color_balance_set_value (this, channel, value); \
+} \
+ \
+static gint \
+interface_as_function ## _color_balance_get_value (GstColorBalance * balance, \
+ GstColorBalanceChannel * channel) \
+{ \
+ Type *this = (Type*) balance; \
+ return gst_camerasrc_color_balance_get_value(this, channel); \
+} \
+ \
+void \
+interface_as_function ## _color_balance_interface_init (GstColorBalanceClass * klass) \
+{ \
+ GST_COLOR_BALANCE_TYPE (klass) = GST_COLOR_BALANCE_HARDWARE; \
+ \
+ /* default virtual functions */ \
+ klass->list_channels = interface_as_function ## _color_balance_list_channels; \
+ klass->set_value = interface_as_function ## _color_balance_set_value; \
+ klass->get_value = interface_as_function ## _color_balance_get_value; \
+} \
+
+#endif /* __GST_CAMERA_SRC_COLOR_BALANCE_H__ */
--- /dev/null
+/* GStreamer
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation <multimedia@maemo.org>
+ *
+ * gstcameraphotoiface.c: Photo interface implementation for camerasrc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <gst/gst.h>
+
+#include "gstcameraphotoiface.h"
+#include "gstcamerasrc.h"
+
+GST_DEBUG_CATEGORY_EXTERN (gst_camerasrc_debug);
+#define GST_CAT_DEFAULT gst_camerasrc_debug
+
+
+static gboolean
+gst_camerasrc_photo_parse_capture_caps (GstCameraSrc *camerasrc,
+ GstCaps *op_mode_caps);
+static gboolean
+gst_camerasrc_photo_parse_preview_caps (GstCameraSrc *camerasrc,
+ GstCaps *op_mode_caps);
+
+
+/*
+ *
+ */
+GstPhotoCaps
+gst_camerasrc_photo_get_capabilities (GstCameraSrc *camerasrc)
+{
+ GstCameraSrcClass *bclass;
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ /* FIXME: driver might not be initialized yet */
+ return bclass->get_capabilities (camerasrc);
+}
+
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_prepare_for_capture (GstCameraSrc *camerasrc,
+ GstPhotoCapturePrepared func,
+ GstCaps *desired_caps,
+ gpointer user_data)
+{
+ GstCameraSrcClass *bclass;
+ gboolean use_vf_caps = TRUE;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ g_mutex_lock (camerasrc->state_lock);
+
+ camerasrc->prep_func = func;
+ camerasrc->prep_udata = user_data;
+
+ if (!camerasrc->capture_resolution_set) {
+ if (desired_caps) {
+ GstStructure *cstr;
+
+ GST_DEBUG_OBJECT (camerasrc, "parsing capture caps");
+
+ cstr = gst_caps_get_structure (desired_caps, 0);
+
+ /* FIXME: Don't require FPS in capture caps */
+ if (gst_structure_get_int (cstr, "width",
+ (gint *) &camerasrc->capture_w) &&
+ gst_structure_get_int (cstr, "height",
+ (gint *) &camerasrc->capture_h) &&
+ gst_structure_get_fraction (cstr, "framerate",
+ (gint *) &camerasrc->capture_fps_n,
+ (gint *) &camerasrc->capture_fps_d))
+ {
+ if (gst_structure_has_field (cstr, "format")) {
+ gst_structure_get_fourcc (cstr, "format", &camerasrc->capture_fourcc);
+ }
+ else {
+ /* If color format is not set, use the viewfinder format then */
+ GST_DEBUG_OBJECT (camerasrc, "using viewfinder color format");
+ camerasrc->capture_fourcc = camerasrc->current_fourcc;
+ }
+ use_vf_caps = FALSE;
+ }
+ }
+
+ if (use_vf_caps) {
+ GST_DEBUG_OBJECT (camerasrc, "given caps inadequate, using VF caps");
+
+ camerasrc->capture_w = camerasrc->current_w;
+ camerasrc->capture_h = camerasrc->current_h;
+ camerasrc->capture_fps_n = camerasrc->fps_n;
+ camerasrc->capture_fps_d = camerasrc->fps_d;
+ camerasrc->capture_fourcc = camerasrc->current_fourcc;
+ }
+ }
+
+ GST_DEBUG_OBJECT (camerasrc, "starting preparations for capture (%dx%d @ %f)",
+ camerasrc->capture_w, camerasrc->capture_h,
+ (gfloat) camerasrc->capture_fps_n / camerasrc->capture_fps_d);
+
+ camerasrc->photo_capture_phase = GST_CAMERA_CAPTURE_START;
+
+ GST_DEBUG_OBJECT (camerasrc, "calling unlock");
+ /* Tell subclass to interrupt frame grabbing */
+ if (bclass->unlock) {
+ bclass->unlock (camerasrc);
+ }
+ GST_DEBUG_OBJECT (camerasrc, "unlock returned");
+
+ g_mutex_unlock (camerasrc->state_lock);
+
+ return TRUE;
+}
+
+
+/*
+ *
+ */
+void
+gst_camerasrc_photo_ready_for_capture (GstCameraSrc *camerasrc,
+ GstCaps *newcaps)
+{
+ GST_DEBUG_OBJECT (camerasrc, "prepare for capture is complete");
+
+ if (camerasrc->prep_func) {
+ camerasrc->prep_func (camerasrc->prep_udata, newcaps);
+ camerasrc->prep_func = NULL;
+ camerasrc->prep_udata = NULL;
+ }
+ GST_DEBUG_OBJECT (camerasrc, "callback returned");
+}
+
+
+/*
+ *
+ */
+static char *
+create_debug_string (const char *base_str, GType type, gint value)
+{
+ GTypeClass *t = g_type_class_ref (type);
+ GEnumValue *val = g_enum_get_value (G_ENUM_CLASS (t), value);
+ gchar *ret = g_strconcat (base_str, val->value_nick, NULL);
+ g_type_class_unref (t);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_set_ev_compensation (GstCameraSrc *camerasrc,
+ gfloat ev_comp)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+
+ if (ev_comp >= -2.5 && ev_comp <= 2.5)
+ {
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ camerasrc->photoconf.ev_compensation = ev_comp;
+
+ if (bclass->is_active (camerasrc)) {
+ ret = bclass->write_settings (camerasrc, &camerasrc->photoconf, FALSE);
+ }
+ GST_DEBUG_OBJECT (camerasrc, "set EV: %.2f, ret = %d", ev_comp, ret);
+ } else {
+ GST_DEBUG_OBJECT (camerasrc, "requested ev compensation value out of range");
+ ret = FALSE;
+ }
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_get_ev_compensation (GstCameraSrc *camerasrc,
+ gfloat *ev_comp)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ if (bclass->is_active (camerasrc)) {
+ ret = bclass->read_settings (camerasrc, &camerasrc->photoconf);
+ }
+ *ev_comp = camerasrc->photoconf.ev_compensation;
+ GST_DEBUG_OBJECT (camerasrc, "got ev compensation: %.2f, ret = %d",
+ *ev_comp, ret);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_set_iso_speed (GstCameraSrc *camerasrc,
+ guint iso_speed)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ camerasrc->photoconf.iso_speed = iso_speed;
+
+ if (bclass->is_active (camerasrc)) {
+ return bclass->write_settings (camerasrc, &camerasrc->photoconf, FALSE);
+}
+ GST_DEBUG_OBJECT (camerasrc, "set ISO: %d, ret = %d", iso_speed, ret);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_get_iso_speed (GstCameraSrc *camerasrc,
+ guint *iso_speed)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ if (bclass->is_active (camerasrc)) {
+ ret = bclass->read_settings (camerasrc, &camerasrc->photoconf);
+ }
+ *iso_speed = camerasrc->photoconf.iso_speed;
+ GST_DEBUG_OBJECT (camerasrc, "got iso speed: %d, ret = %d", *iso_speed, ret);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_set_aperture (GstCameraSrc *camerasrc,
+ guint aperture)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ camerasrc->photoconf.aperture = aperture;
+
+ if (bclass->is_active (camerasrc)) {
+ ret = bclass->write_settings (camerasrc, &camerasrc->photoconf, FALSE);
+}
+ GST_DEBUG_OBJECT (camerasrc, "set aperture: %d, ret = %d", aperture, ret);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_get_aperture (GstCameraSrc *camerasrc,
+ guint *aperture)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ if (bclass->is_active (camerasrc)) {
+ ret = bclass->read_settings (camerasrc, &camerasrc->photoconf);
+ }
+ *aperture = camerasrc->photoconf.aperture;
+ GST_DEBUG_OBJECT (camerasrc, "got aperture: %d, ret = %d", *aperture, ret);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_set_exposure (GstCameraSrc *camerasrc,
+ guint32 exposure)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ camerasrc->photoconf.exposure = exposure;
+
+ if (bclass->is_active (camerasrc)) {
+ ret = bclass->write_settings (camerasrc, &camerasrc->photoconf, FALSE);
+ }
+ GST_DEBUG_OBJECT (camerasrc, "set exposure: %d, ret = %d", exposure, ret);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_get_exposure (GstCameraSrc *camerasrc,
+ guint32 *exposure)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ if (bclass->is_active (camerasrc)) {
+ ret = bclass->read_settings (camerasrc, &camerasrc->photoconf);
+ }
+ *exposure = camerasrc->photoconf.exposure;
+ GST_DEBUG_OBJECT (camerasrc, "got exposure: %d, ret = %d", *exposure, ret);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_set_wb_mode (GstCameraSrc *camerasrc,
+ GstWhiteBalanceMode mode)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+ gchar *dstr;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ camerasrc->photoconf.wb_mode = mode;
+
+ if (bclass->is_active (camerasrc)) {
+ ret = bclass->write_settings (camerasrc, &camerasrc->photoconf, FALSE);
+ }
+ dstr = create_debug_string ("AWB:", GST_TYPE_WHITE_BALANCE_MODE, mode);
+ GST_DEBUG_OBJECT (camerasrc, "set %s, ret = %d", dstr, ret);
+ g_free (dstr);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_get_wb_mode (GstCameraSrc *camerasrc,
+ GstWhiteBalanceMode *mode)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ if (bclass->is_active (camerasrc)) {
+ ret = bclass->read_settings (camerasrc, &camerasrc->photoconf);
+ }
+ *mode = camerasrc->photoconf.wb_mode;
+ GST_DEBUG_OBJECT (camerasrc, "got AWB mode:%d, ret = %d", *mode, ret);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_set_tone_mode (GstCameraSrc *camerasrc,
+ GstColourToneMode mode)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+ gchar *dstr;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ camerasrc->photoconf.tone_mode = mode;
+
+ if (bclass->is_active (camerasrc)) {
+ ret = bclass->write_settings (camerasrc, &camerasrc->photoconf, FALSE);
+ }
+ dstr = create_debug_string ("tone:", GST_TYPE_COLOUR_TONE_MODE, mode);
+ GST_DEBUG_OBJECT (camerasrc, "set %s, ret = %d", dstr, ret);
+ g_free (dstr);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_get_tone_mode (GstCameraSrc *camerasrc,
+ GstColourToneMode *mode)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ if (bclass->is_active (camerasrc)) {
+ ret = bclass->read_settings (camerasrc, &camerasrc->photoconf);
+ }
+ *mode = camerasrc->photoconf.tone_mode;
+ GST_DEBUG_OBJECT (camerasrc, "got tone mode: %d, ret = %d", *mode, ret);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_set_scene_mode (GstCameraSrc *camerasrc,
+ GstSceneMode mode)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+ gchar *dstr;
+ GParamSpec **properties;
+ gpointer photo_iface;
+ guint i, n_properties = 0;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ camerasrc->photoconf.scene_mode = mode;
+
+ if (bclass->is_active (camerasrc)) {
+ ret = bclass->write_settings (camerasrc, &camerasrc->photoconf, TRUE);
+ if (ret) {
+ /* Read the changed parameters to local settings cache */
+ bclass->read_settings (camerasrc, &camerasrc->photoconf);
+ /* Notify that changing scene mode might have changed also other
+ interface properties */
+ GST_DEBUG_OBJECT (camerasrc, "notifying interface property changes");
+ photo_iface = g_type_default_interface_ref (GST_TYPE_PHOTOGRAPHY);
+ properties =
+ g_object_interface_list_properties (photo_iface, &n_properties);
+ if (properties) {
+ for (i = 0; i < n_properties; i++) {
+ const gchar *name = g_param_spec_get_name (properties[i]);
+ g_object_notify (G_OBJECT (camerasrc), name);
+ }
+ }
+ g_type_default_interface_unref (photo_iface);
+ }
+ }
+ dstr = create_debug_string ("scene:", GST_TYPE_SCENE_MODE, mode);
+ GST_DEBUG_OBJECT (camerasrc, "set %s, ret = %d", dstr, ret);
+ g_free (dstr);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_get_scene_mode (GstCameraSrc *camerasrc,
+ GstSceneMode *mode)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ if (bclass->is_active (camerasrc)) {
+ ret = bclass->read_settings (camerasrc, &camerasrc->photoconf);
+ }
+ *mode = camerasrc->photoconf.scene_mode;
+ GST_DEBUG_OBJECT (camerasrc, "got scene mode: %d, ret = %d", *mode, ret);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_set_flash_mode (GstCameraSrc *camerasrc,
+ GstFlashMode mode)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+ gchar *dstr;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ camerasrc->photoconf.flash_mode = mode;
+
+ if (bclass->is_active (camerasrc)) {
+ ret = bclass->write_settings (camerasrc, &camerasrc->photoconf, FALSE);
+ }
+ dstr = create_debug_string ("flash:", GST_TYPE_FLASH_MODE, mode);
+ GST_DEBUG_OBJECT (camerasrc, "set %s, ret = %d", dstr, ret);
+ g_free (dstr);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_get_flash_mode (GstCameraSrc *camerasrc,
+ GstFlashMode *mode)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ if (bclass->is_active (camerasrc)) {
+ ret = bclass->read_settings (camerasrc, &camerasrc->photoconf);
+ }
+ *mode = camerasrc->photoconf.flash_mode;
+ GST_DEBUG_OBJECT (camerasrc, "got flash mode: %d, ret = %d", *mode, ret);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_set_zoom (GstCameraSrc *camerasrc, gint zoom)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ camerasrc->photoconf.zoom = zoom;
+
+ GST_DEBUG_OBJECT (camerasrc, "setting zoom to %d", camerasrc->photoconf.zoom);
+
+ if (bclass->set_zoom) {
+ ret = bclass->set_zoom (camerasrc, (gfloat) camerasrc->photoconf.zoom/100);
+ }
+ else {
+ /* FIXME: Check if the zoom is within known limits */
+ }
+ GST_DEBUG_OBJECT (camerasrc, "setting zoom %s", ret ? "success" : "failed");
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_get_zoom (GstCameraSrc *camerasrc, gint *zoom)
+{
+ *zoom = camerasrc->photoconf.zoom;
+
+ GST_DEBUG_OBJECT (camerasrc, "current zoom = %d", *zoom);
+ return TRUE;
+}
+
+
+/*
+*
+*/
+gboolean
+gst_camerasrc_photo_set_flicker_mode (GstCameraSrc *camerasrc,
+ GstFlickerReductionMode mode)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+ gchar *dstr;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ camerasrc->photoconf.flicker_mode = mode;
+
+ if (bclass->is_active (camerasrc)) {
+ ret = bclass->write_settings (camerasrc, &camerasrc->photoconf, FALSE);
+}
+ dstr = create_debug_string ("flicker mode:",
+ GST_TYPE_FLICKER_REDUCTION_MODE, mode);
+
+ GST_DEBUG_OBJECT (camerasrc, "set %s, ret = %d", dstr, ret);
+ g_free (dstr);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_get_flicker_mode (GstCameraSrc *camerasrc,
+ GstFlickerReductionMode *mode)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ if (bclass->is_active (camerasrc)) {
+ ret = bclass->read_settings (camerasrc, &camerasrc->photoconf);
+ }
+ *mode = camerasrc->photoconf.flicker_mode;
+ GST_DEBUG_OBJECT (camerasrc, "got flicker mode: %d, ret = %d", *mode, ret);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_set_focus_mode (GstCameraSrc *camerasrc,
+ GstFocusMode mode)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+ gchar *dstr;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ camerasrc->photoconf.focus_mode = mode;
+
+ if (bclass->is_active (camerasrc)) {
+ ret = bclass->write_settings (camerasrc, &camerasrc->photoconf, FALSE);
+ }
+ dstr = create_debug_string ("focus mode:", GST_TYPE_FOCUS_MODE, mode);
+ GST_DEBUG_OBJECT (camerasrc, "set %s, ret = %d", dstr, ret);
+ g_free (dstr);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_get_focus_mode (GstCameraSrc *camerasrc,
+ GstFocusMode *mode)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ if (bclass->is_active (camerasrc)) {
+ ret = bclass->read_settings (camerasrc, &camerasrc->photoconf);
+ }
+ *mode = camerasrc->photoconf.focus_mode;
+ GST_DEBUG_OBJECT (camerasrc, "got focus mode: %d, ret = %d", *mode, ret);
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+void
+gst_camerasrc_photo_set_autofocus (GstCameraSrc *camerasrc,
+ gboolean on)
+{
+ GST_DEBUG_OBJECT (camerasrc, "setting autofocus %s", on ? "ON" : "OFF");
+
+ g_mutex_lock (camerasrc->af_lock);
+
+ if (on) {
+ camerasrc->requested_af_mode = AF_ON_REQUESTED;
+ }
+ else {
+ camerasrc->requested_af_mode = AF_OFF_REQUESTED;
+ }
+
+ g_mutex_unlock (camerasrc->af_lock);
+
+ GST_DEBUG_OBJECT (camerasrc, "setting autofocus done");
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_set_config (GstCameraSrc *camerasrc,
+ GstPhotoSettings * config)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = TRUE;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ if (bclass->is_active (camerasrc)) {
+ gboolean scene_override =
+ config->scene_mode != GST_PHOTOGRAPHY_SCENE_MODE_MANUAL ? TRUE : FALSE;
+
+ ret = bclass->write_settings (camerasrc, config, scene_override);
+
+ if (ret && scene_override) {
+ ret = bclass->read_settings (camerasrc, config);
+ }
+ }
+ GST_DEBUG_OBJECT (camerasrc, "set config, ret = %d", ret);
+
+ if (ret) {
+ memcpy (&camerasrc->photoconf, config, sizeof (GstPhotoSettings));
+ }
+
+ return ret;
+
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_get_config (GstCameraSrc *camerasrc,
+ GstPhotoSettings * config)
+{
+ memcpy (config, &camerasrc->photoconf, sizeof (GstPhotoSettings));
+
+ GST_DEBUG_OBJECT (camerasrc, "got config");
+ return TRUE;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_set_format (GstCameraSrc *camerasrc,
+ GstOperationMode op_mode,
+ GstCaps * op_mode_caps)
+{
+ gboolean ret = TRUE;
+
+ GST_DEBUG_OBJECT (camerasrc, "Caps received: %" GST_PTR_FORMAT, op_mode_caps);
+
+ if (op_mode == GST_PHOTOGRAPHY_OPERATION_MODE_IMAGE_CAPTURE) {
+ ret = gst_camerasrc_photo_parse_capture_caps (camerasrc, op_mode_caps);
+ }
+ else if (op_mode == GST_PHOTOGRAPHY_OPERATION_MODE_PREVIEW) {
+ ret = gst_camerasrc_photo_parse_preview_caps (camerasrc, op_mode_caps);
+ }
+ else {
+ GST_WARNING ("Trying to set unsupported operation mode");
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+GstCaps *
+gst_camerasrc_photo_get_format (GstCameraSrc *camerasrc,
+ GstOperationMode op_mode)
+{
+ GstCaps *ret = NULL;
+
+ /* FIXME: Check if the format is set or not */
+
+ if (op_mode == GST_PHOTOGRAPHY_OPERATION_MODE_IMAGE_CAPTURE &&
+ camerasrc->capture_resolution_set)
+ {
+ ret = gst_caps_new_simple ("video/x-raw-yuv",
+ "format", GST_TYPE_FOURCC, camerasrc->capture_fourcc,
+ "width", G_TYPE_INT, camerasrc->capture_w,
+ "height", G_TYPE_INT, camerasrc->capture_h,
+ "framerate", GST_TYPE_FRACTION, camerasrc->capture_fps_n,
+ camerasrc->capture_fps_d,
+ NULL);
+
+ GST_DEBUG_OBJECT (camerasrc, "get format (capture): %" GST_PTR_FORMAT, ret);
+ }
+ else if (op_mode == GST_PHOTOGRAPHY_OPERATION_MODE_PREVIEW &&
+ camerasrc->preview_resolution_set)
+ {
+ ret = gst_caps_new_simple ("video/x-raw-yuv",
+ "format", GST_TYPE_FOURCC, camerasrc->preview_fourcc,
+ "width", G_TYPE_INT, camerasrc->preview_w,
+ "height", G_TYPE_INT, camerasrc->preview_h,
+ NULL);
+
+ GST_DEBUG_OBJECT (camerasrc, "get format (preview): %" GST_PTR_FORMAT, ret);
+ }
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_get_property (GstCameraSrc *camerasrc,
+ guint prop_id, GValue * value)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = FALSE;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ switch (prop_id) {
+ case PROP_WB_MODE:
+ {
+ GstWhiteBalanceMode wb_mode;
+ GST_DEBUG_OBJECT (camerasrc, "==== GETTING PROP_WB_MODE ====");
+ if (gst_camerasrc_photo_get_wb_mode (camerasrc, &wb_mode)) {
+ g_value_set_enum (value, wb_mode);
+ }
+ ret = TRUE;
+ break;
+ }
+ case PROP_COLOUR_TONE:
+ {
+ GstColourToneMode tone;
+ GST_DEBUG_OBJECT (camerasrc, "==== GETTING PROP_COLOUR_TONE ====");
+ if (gst_camerasrc_photo_get_tone_mode (camerasrc, &tone)) {
+ g_value_set_enum (value, tone);
+ }
+ ret = TRUE;
+ break;
+ }
+ case PROP_SCENE_MODE:
+ {
+ GstSceneMode scene;
+ GST_DEBUG_OBJECT (camerasrc, "==== GETTING PROP_SCENE_MODE ====");
+ if (gst_camerasrc_photo_get_scene_mode (camerasrc, &scene)) {
+ g_value_set_enum (value, scene);
+ }
+ ret = TRUE;
+ break;
+ }
+ case PROP_FLASH_MODE:
+ {
+ GstFlashMode flash;
+ GST_DEBUG_OBJECT (camerasrc, "==== GETTING PROP_FLASH_MODE ====");
+ if (gst_camerasrc_photo_get_flash_mode (camerasrc, &flash)) {
+ g_value_set_enum (value, flash);
+ }
+ ret = TRUE;
+ break;
+ }
+ case PROP_CAPABILITIES:
+ {
+ gulong capabilities;
+ GST_DEBUG_OBJECT (camerasrc, "==== GETTING PROP_CAPABILITIES ====");
+ capabilities = (gulong) gst_camerasrc_photo_get_capabilities (camerasrc);
+ g_value_set_ulong (value, capabilities);
+ ret = TRUE;
+ break;
+ }
+ case PROP_EV_COMP:
+ {
+ gfloat ev_comp;
+ GST_DEBUG_OBJECT (camerasrc, "==== GETTING PROP_EV_COMP ====");
+ if (gst_camerasrc_photo_get_ev_compensation (camerasrc, &ev_comp)) {
+ g_value_set_float (value, ev_comp);
+ }
+ ret = TRUE;
+ break;
+ }
+ case PROP_ISO_SPEED:
+ {
+ guint iso_speed;
+ GST_DEBUG_OBJECT (camerasrc, "==== GETTING PROP_ISO_SPEED ====");
+ if (gst_camerasrc_photo_get_iso_speed (camerasrc, &iso_speed)) {
+ g_value_set_uint (value, iso_speed);
+ }
+ ret = TRUE;
+ break;
+ }
+ case PROP_APERTURE:
+ {
+ guint aperture;
+ GST_DEBUG_OBJECT (camerasrc, "==== GETTING PROP_APERTURE ====");
+ if (gst_camerasrc_photo_get_aperture (camerasrc, &aperture)) {
+ g_value_set_uint (value, aperture);
+ }
+ ret = TRUE;
+ break;
+ }
+ case PROP_EXPOSURE:
+ {
+ guint32 exposure;
+ GST_DEBUG_OBJECT (camerasrc, "==== GETTING PROP_EXPOSURE ====");
+ if (gst_camerasrc_photo_get_exposure (camerasrc, &exposure)) {
+ g_value_set_uint (value, exposure);
+ }
+ ret = TRUE;
+ break;
+ }
+ case PROP_ZOOM:
+ {
+ gint zoom;
+ GST_DEBUG_OBJECT (camerasrc, "==== GETTING PROP_ZOOM ====");
+ if (gst_camerasrc_photo_get_zoom (camerasrc, &zoom)) {
+ g_value_set_int (value, zoom);
+ }
+ ret = TRUE;
+ break;
+ }
+ case PROP_FLICKER_MODE:
+ {
+ GstFlickerReductionMode flicker_mode;
+ GST_DEBUG_OBJECT (camerasrc, "==== GETTING PROP_FLICKER_MODE ====");
+ if (gst_camerasrc_photo_get_flicker_mode (camerasrc, &flicker_mode)) {
+ g_value_set_enum (value, flicker_mode);
+ }
+ ret = TRUE;
+ break;
+ }
+ case PROP_FOCUS_MODE:
+ {
+ GstFocusMode focus_mode;
+ GST_DEBUG_OBJECT (camerasrc, "==== GETTING PROP_FOCUS_MODE ====");
+ if (gst_camerasrc_photo_get_focus_mode (camerasrc, &focus_mode)) {
+ g_value_set_enum (value, focus_mode);
+ }
+ ret = TRUE;
+ break;
+ }
+ case PROP_IMAGE_CAPTURE_CAPS:
+ {
+ GstCaps *caps;
+ GST_DEBUG_OBJECT (camerasrc, "==== GETTING PROP_IMAGE_CAPTURE_CAPS ====");
+ caps = bclass->get_supported_caps (camerasrc,
+ GST_PHOTOGRAPHY_OPERATION_MODE_IMAGE_CAPTURE);
+ if (!caps) {
+ caps = gst_caps_new_empty ();
+ }
+ gst_value_set_caps (value, caps);
+ gst_caps_unref (caps);
+ ret = TRUE;
+ break;
+ }
+ case PROP_IMAGE_PREVIEW_CAPS:
+ {
+ GstCaps *caps;
+ GST_DEBUG_OBJECT (camerasrc, "==== GETTING PROP_IMAGE_PREVIEW_CAPS ====");
+ caps = bclass->get_supported_caps (camerasrc,
+ GST_PHOTOGRAPHY_OPERATION_MODE_PREVIEW);
+ if (!caps) {
+ caps = gst_caps_new_empty ();
+ }
+ gst_value_set_caps (value, caps);
+ gst_caps_unref (caps);
+ ret = TRUE;
+ break;
+ }
+ case PROP_AUTOFOCUS:
+ {
+ GST_DEBUG_OBJECT (camerasrc, "==== GETTING PROP_AUTOFOCUS ====");
+ g_mutex_lock (camerasrc->af_lock);
+ if (camerasrc->photo_capture_phase == GST_CAMERA_AUTOFOCUS ||
+ camerasrc->requested_af_mode == AF_ON_REQUESTED)
+ {
+ g_value_set_boolean (value, TRUE);
+ } else {
+ g_value_set_boolean (value, FALSE);
+ }
+ g_mutex_unlock (camerasrc->af_lock);
+
+ ret = TRUE;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+
+/*
+ *
+ */
+gboolean
+gst_camerasrc_photo_set_property (GstCameraSrc *camerasrc,
+ guint prop_id, const GValue * value)
+{
+ gboolean ret = FALSE;
+
+ switch (prop_id) {
+ case PROP_WB_MODE:
+ GST_DEBUG_OBJECT (camerasrc, "==== SETTING PROP_WB_MODE ====");
+ gst_camerasrc_photo_set_wb_mode (camerasrc, g_value_get_enum (value));
+ ret = TRUE;
+ break;
+ case PROP_COLOUR_TONE:
+ GST_DEBUG_OBJECT (camerasrc, "==== SETTING PROP_COLOUR_TONE ====");
+ gst_camerasrc_photo_set_tone_mode (camerasrc, g_value_get_enum (value));
+ ret = TRUE;
+ break;
+ case PROP_SCENE_MODE:
+ GST_DEBUG_OBJECT (camerasrc, "==== SETTING PROP_SCENE_MODE ====");
+ gst_camerasrc_photo_set_scene_mode (camerasrc, g_value_get_enum (value));
+ ret = TRUE;
+ break;
+ case PROP_FLASH_MODE:
+ GST_DEBUG_OBJECT (camerasrc, "==== SETTING PROP_FLASH_MODE ====");
+ gst_camerasrc_photo_set_flash_mode (camerasrc, g_value_get_enum (value));
+ ret = TRUE;
+ break;
+ case PROP_EV_COMP:
+ GST_DEBUG_OBJECT (camerasrc, "==== SETTING PROP_EV_COMP ====");
+ gst_camerasrc_photo_set_ev_compensation (camerasrc, g_value_get_float (value));
+ ret = TRUE;
+ break;
+ case PROP_ISO_SPEED:
+ GST_DEBUG_OBJECT (camerasrc, "==== SETTING PROP_ISO_SPEED ====");
+ gst_camerasrc_photo_set_iso_speed (camerasrc, g_value_get_uint (value));
+ ret = TRUE;
+ break;
+ case PROP_APERTURE:
+ GST_DEBUG_OBJECT (camerasrc, "==== SETTING PROP_APERTURE ====");
+ gst_camerasrc_photo_set_aperture (camerasrc, g_value_get_uint (value));
+ ret = TRUE;
+ break;
+ case PROP_EXPOSURE:
+ GST_DEBUG_OBJECT (camerasrc, "==== SETTING PROP_EXPOSURE ====");
+ gst_camerasrc_photo_set_exposure (camerasrc, g_value_get_uint (value));
+ ret = TRUE;
+ break;
+ case PROP_ZOOM:
+ GST_DEBUG_OBJECT (camerasrc, "==== SETTING PROP_ZOOM ====");
+ gst_camerasrc_photo_set_zoom (camerasrc, g_value_get_int (value));
+ ret = TRUE;
+ break;
+ case PROP_FLICKER_MODE:
+ GST_DEBUG_OBJECT (camerasrc, "==== SETTING PROP_FLICKER_MODE ====");
+ gst_camerasrc_photo_set_flicker_mode (camerasrc, g_value_get_enum (value));
+ ret = TRUE;
+ break;
+ case PROP_FOCUS_MODE:
+ GST_DEBUG_OBJECT (camerasrc, "==== SETTING PROP_FOCUS_MODE ====");
+ gst_camerasrc_photo_set_focus_mode (camerasrc, g_value_get_enum (value));
+ ret = TRUE;
+ break;
+ case PROP_AUTOFOCUS:
+ GST_DEBUG_OBJECT (camerasrc, "==== SETTING PROP_AUTOFOCUS ====");
+ gst_camerasrc_photo_set_autofocus (camerasrc, g_value_get_boolean (value));
+ ret = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+
+/*** Internal API ***/
+
+static gboolean
+gst_camerasrc_photo_parse_capture_caps (GstCameraSrc *camerasrc,
+ GstCaps *op_mode_caps)
+{
+ GstCameraSrcClass *bclass;
+
+ gboolean ret = TRUE;
+ GstStructure *cstr;
+ guint32 fcc_format;
+ gint tmp_fps_n = 0;
+ gint tmp_fps_d = 0;
+ gint tmp_w = 0;
+ gint tmp_h = 0;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ GST_DEBUG_OBJECT (camerasrc, "Parsing image capture caps");
+
+ if (op_mode_caps == NULL) {
+ camerasrc->capture_resolution_set = FALSE;
+ GST_DEBUG_OBJECT (camerasrc, "NULL caps received for image capture");
+ goto done;
+ }
+
+ cstr = gst_caps_get_structure (op_mode_caps, 0);
+
+ /* FIXME: Use VF format if fourcc is not given */
+ /* FIXME: Don't require FPS here */
+ if (gst_structure_get_fourcc (cstr, "format", &fcc_format) &&
+ gst_structure_get_int (cstr, "width", &tmp_w) &&
+ gst_structure_get_int (cstr, "height", &tmp_h) &&
+ gst_structure_get_fraction (cstr, "framerate", &tmp_fps_n, &tmp_fps_d))
+ {
+ /* check if the requested fourcc format is supported */
+ GstCaps * s_caps = NULL;
+
+ /* get camsrc sourcepad caps, because the pad has
+ * caps-template including supported formats */
+ s_caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD
+ (camerasrc)));
+
+ /* if intersection is empty -> provided caps not supported */
+ if (!gst_caps_can_intersect (op_mode_caps, s_caps)) {
+ GST_WARNING_OBJECT (camerasrc,
+ "Unsupported fourcc format provided by caller");
+ ret = FALSE;
+ }
+
+ /* Check that the requested resolution is not the same as what is
+ * currently configured to be in use. If so, no need to set it again.
+ */
+ if ((camerasrc->capture_w != tmp_w ||
+ camerasrc->capture_h != tmp_h ||
+ camerasrc->capture_fourcc != fcc_format) &&
+ ret == TRUE)
+ {
+ GST_DEBUG_OBJECT (camerasrc,
+ "set width: %d , height: %d , fps_n: %d , fps_d :%d , format: %"
+ GST_FOURCC_FORMAT, tmp_w, tmp_h, tmp_fps_n, tmp_fps_d,
+ GST_FOURCC_ARGS (fcc_format));
+
+ ret = bclass->set_capture (camerasrc,
+ GST_PHOTOGRAPHY_OPERATION_MODE_IMAGE_CAPTURE, FALSE, &fcc_format,
+ (guint *) &tmp_w, (guint *) &tmp_h, NULL, NULL);
+
+ if (ret) {
+ camerasrc->capture_w = tmp_w;
+ camerasrc->capture_h = tmp_h;
+ camerasrc->capture_fps_n = tmp_fps_n;
+ camerasrc->capture_fps_d = tmp_fps_d;
+ camerasrc->capture_fourcc = fcc_format;
+ camerasrc->capture_resolution_set = TRUE;
+
+ /* Write the assigned values back to the caps structure if possible */
+ if (GST_CAPS_REFCOUNT_VALUE (op_mode_caps) == 1) {
+ gst_caps_set_simple (op_mode_caps,
+ "width", G_TYPE_INT, camerasrc->capture_w,
+ "height", G_TYPE_INT, camerasrc->capture_h,
+ "format", GST_TYPE_FOURCC, camerasrc->capture_fourcc,
+ NULL);
+ }
+
+ /* It may not be possible to create the preview with previously
+ * given resolution. Therefore we cancel the preview creation */
+ gst_camerasrc_photo_parse_preview_caps (camerasrc, NULL);
+
+ /* Notify that supported preview caps may have changed */
+ g_object_notify (G_OBJECT (camerasrc),
+ GST_PHOTOGRAPHY_PROP_IMAGE_PREVIEW_SUPPORTED_CAPS);
+ }
+ } else {
+ GST_DEBUG_OBJECT (camerasrc, "format not set");
+ ret = FALSE;
+ }
+ if (s_caps)
+ gst_caps_unref (s_caps);
+
+ } else {
+ GST_DEBUG_OBJECT (camerasrc, "Unable to parse given caps");
+ ret = FALSE;
+ }
+
+done:
+
+ return ret;
+}
+
+
+static gboolean
+gst_camerasrc_photo_parse_preview_caps (GstCameraSrc *camerasrc,
+ GstCaps *op_mode_caps)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = FALSE;
+ guint32 fourcc = 0;
+ gint tmp_w = 0;
+ gint tmp_h = 0;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ if (op_mode_caps == NULL) {
+ /* Setting NULL caps means canceling the preview image creation process.
+ * In this case resolution 0x0 will be given to subclass */
+ GST_DEBUG_OBJECT (camerasrc, "NULL caps received for preview image");
+ ret = TRUE;
+ }
+ else {
+ GstStructure *cstr;
+
+ GST_DEBUG_OBJECT (camerasrc, "parsing preview caps");
+
+ cstr = gst_caps_get_structure (op_mode_caps, 0);
+
+ /* FIXME: Use VF format if fourcc is not given */
+ if (gst_structure_get_fourcc (cstr, "format", &fourcc) &&
+ gst_structure_get_int (cstr, "width", &tmp_w) &&
+ gst_structure_get_int (cstr, "height", &tmp_h))
+ {
+#if 0
+ /* check if the requested fourcc format is supported */
+ GstCaps * s_caps = NULL;
+ GstCaps * r_caps = NULL;
+
+ /* get camsrc sourcepad caps, because the pad has
+ * caps-template including supported formats */
+ s_caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD
+ (camerasrc)));
+ /* take an intersection between sourcepad caps and provided caps */
+ r_caps = gst_caps_intersect (op_mode_caps, s_caps);
+
+ /* if EMPTY or NULL => provided caps not supported as not set in sourcepad */
+ if (r_caps == NULL || gst_caps_is_empty (r_caps)) {
+ GST_WARNING_OBJECT (camerasrc,
+ "Unsupported fourcc format provided by caller");
+ ret = FALSE;
+ }
+ if (s_caps)
+ gst_caps_unref (s_caps);
+ if (r_caps)
+ gst_caps_unref (r_caps);
+#endif
+ ret = TRUE;
+ }
+ else {
+ GST_DEBUG_OBJECT (camerasrc, "Unable to parse given caps");
+ ret = FALSE;
+ }
+ }
+
+ /* Check that the requested resolution is not the same as what is
+ * currently configured to be in use. If so, no need to set it again.
+ */
+ if (ret && (camerasrc->preview_w != tmp_w || camerasrc->preview_h != tmp_h ||
+ camerasrc->preview_fourcc != fourcc))
+ {
+ GST_DEBUG_OBJECT (camerasrc,
+ "set preview width: %d, height: %d, format: %"
+ GST_FOURCC_FORMAT, tmp_w, tmp_h, GST_FOURCC_ARGS (fourcc));
+
+ ret = bclass->set_capture (camerasrc,
+ GST_PHOTOGRAPHY_OPERATION_MODE_PREVIEW, FALSE,
+ &fourcc, (guint *) &tmp_w, (guint *) &tmp_h, NULL, NULL);
+
+ if (fourcc == 0) {
+ /* Special case: preview image creation is canceled (NULL caps)*/
+ camerasrc->preview_resolution_set = FALSE;
+ ret = TRUE;
+ }
+ else {
+ if (ret && GST_CAPS_REFCOUNT_VALUE (op_mode_caps) == 1) {
+ /* Write the assigned values back to the caps structure */
+ gst_caps_set_simple (op_mode_caps,
+ "width", G_TYPE_INT, tmp_w,
+ "height", G_TYPE_INT, tmp_h,
+ "format", GST_TYPE_FOURCC, fourcc,
+ NULL);
+ }
+
+ GST_DEBUG_OBJECT (camerasrc,
+ "selected preview width: %d, height: %d, format: %"
+ GST_FOURCC_FORMAT, tmp_w, tmp_h, GST_FOURCC_ARGS (fourcc));
+
+ camerasrc->preview_resolution_set = ret;
+ }
+ } else {
+ GST_DEBUG_OBJECT (camerasrc, "format not set");
+ ret = FALSE;
+ }
+
+ if (ret) {
+ camerasrc->preview_w = tmp_w;
+ camerasrc->preview_h = tmp_h;
+ camerasrc->preview_fourcc = fourcc;
+ }
+
+ return ret;
+}
+
+
+
+
+
--- /dev/null
+/* GStreamer
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation <multimedia@maemo.org>
+ *
+ * gstcameraphotoiface.h: Photo interface implementation for camerasrc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should 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_CAMERA_SRC_PHOTOGRAPHY_H__
+#define __GST_CAMERA_SRC_PHOTOGRAPHY_H__
+
+#include <gst/gst.h>
+#include <gst/interfaces/photography.h>
+
+#include "gstcamerasrc.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+ PROP_0,
+ PROP_ALWAYS_COPY,
+ PROP_CAPTURE_MODE,
+ PROP_VIEWFINDER_MODE,
+ PROP_DRIVER_NAME,
+ PROP_WB_MODE,
+ PROP_COLOUR_TONE,
+ PROP_SCENE_MODE,
+ PROP_FLASH_MODE,
+ PROP_CAPABILITIES,
+ PROP_EV_COMP,
+ PROP_ISO_SPEED,
+ PROP_APERTURE,
+ PROP_EXPOSURE,
+ PROP_ZOOM,
+ PROP_FLICKER_MODE,
+ PROP_FOCUS_MODE,
+ PROP_IMAGE_CAPTURE_CAPS,
+ PROP_IMAGE_PREVIEW_CAPS,
+ PROP_AUTOFOCUS
+} GstCameraSrcProperties;
+
+
+gboolean
+gst_camerasrc_photo_set_ev_compensation (GstCameraSrc * camerasrc,
+ gfloat ev_comp);
+
+gboolean
+gst_camerasrc_photo_get_ev_compensation (GstCameraSrc * camerasrc,
+ gfloat *ev_comp);
+
+gboolean
+gst_camerasrc_photo_set_iso_speed (GstCameraSrc * camerasrc,
+ guint iso_speed);
+
+gboolean
+gst_camerasrc_photo_get_iso_speed (GstCameraSrc * camerasrc,
+ guint *iso_speed);
+
+gboolean
+gst_camerasrc_photo_set_aperture (GstCameraSrc * camerasrc,
+ guint aperture);
+
+gboolean
+gst_camerasrc_photo_get_aperture (GstCameraSrc * camerasrc,
+ guint *aperture);
+
+gboolean
+gst_camerasrc_photo_set_exposure (GstCameraSrc * camerasrc,
+ guint32 exposure);
+
+gboolean
+gst_camerasrc_photo_get_exposure (GstCameraSrc * camerasrc,
+ guint32 *exposure);
+
+gboolean
+gst_camerasrc_photo_set_wb_mode (GstCameraSrc * camerasrc,
+ GstWhiteBalanceMode mode);
+
+gboolean
+gst_camerasrc_photo_get_wb_mode (GstCameraSrc * camerasrc,
+ GstWhiteBalanceMode *mode);
+
+gboolean
+gst_camerasrc_photo_set_tone_mode (GstCameraSrc * camerasrc,
+ GstColourToneMode mode);
+
+gboolean
+gst_camerasrc_photo_get_tone_mode (GstCameraSrc * camerasrc,
+ GstColourToneMode *mode);
+
+gboolean
+gst_camerasrc_photo_set_scene_mode (GstCameraSrc * camerasrc,
+ GstSceneMode mode);
+
+gboolean
+gst_camerasrc_photo_get_scene_mode (GstCameraSrc * camerasrc,
+ GstSceneMode *mode);
+
+gboolean
+gst_camerasrc_photo_set_flash_mode (GstCameraSrc * camerasrc,
+ GstFlashMode mode);
+
+gboolean
+gst_camerasrc_photo_get_flash_mode (GstCameraSrc * camerasrc,
+ GstFlashMode *mode);
+
+gboolean
+gst_camerasrc_photo_set_zoom (GstCameraSrc * camerasrc,
+ gint zoom);
+
+gboolean
+gst_camerasrc_photo_get_zoom (GstCameraSrc * camerasrc,
+ gint *zoom);
+
+gboolean
+gst_camerasrc_photo_set_flicker_mode (GstCameraSrc * camerasrc,
+ GstFlickerReductionMode mode);
+
+gboolean
+gst_camerasrc_photo_get_flicker_mode (GstCameraSrc * camerasrc,
+ GstFlickerReductionMode *mode);
+
+gboolean
+gst_camerasrc_photo_set_focus_mode (GstCameraSrc * camerasrc,
+ GstFocusMode mode);
+gboolean
+gst_camerasrc_photo_get_focus_mode (GstCameraSrc * camerasrc,
+ GstFocusMode *mode);
+
+
+void
+gst_camerasrc_photo_set_autofocus (GstCameraSrc * camerasrc,
+ gboolean on);
+
+gboolean
+gst_camerasrc_photo_prepare_for_capture (GstCameraSrc * camerasrc,
+ GstPhotoCapturePrepared func,
+ GstCaps *capture_caps,
+ gpointer user_data);
+
+GstPhotoCaps
+gst_camerasrc_photo_get_capabilities (GstCameraSrc * camerasrc);
+
+void
+gst_camerasrc_photo_ready_for_capture (GstCameraSrc *camerasrc,
+ GstCaps *selected);
+
+gboolean
+gst_camerasrc_photo_set_config (GstCameraSrc * camerasrc,
+ GstPhotoSettings * config);
+
+gboolean
+gst_camerasrc_photo_get_config (GstCameraSrc * camerasrc,
+ GstPhotoSettings * config);
+
+gboolean
+gst_camerasrc_photo_set_format (GstCameraSrc * camerasrc,
+ GstOperationMode op_mode,
+ GstCaps * op_mode_caps);
+GstCaps *
+gst_camerasrc_photo_get_format (GstCameraSrc * camerasrc,
+ GstOperationMode op_mode);
+
+gboolean
+gst_camerasrc_photo_set_property (GstCameraSrc *camerasrc,
+ guint prop_id,
+ const GValue * value);
+
+gboolean
+gst_camerasrc_photo_get_property (GstCameraSrc *camerasrc,
+ guint prop_id,
+ GValue * value);
+
+#define GST_CAMERA_SRC_PHOTO_FUNCS(Type, interface_as_function, function_name, param_type) \
+ \
+gboolean \
+interface_as_function ## _photo_set_ ## function_name (GstPhotography * photo, \
+ param_type param) \
+{ \
+ Type *this = (Type*) photo; \
+ return gst_camerasrc_photo_set_ ## function_name (this, param); \
+} \
+ \
+gboolean \
+interface_as_function ## _photo_get_ ## function_name (GstPhotography * photo, \
+ param_type * param) \
+{ \
+ Type *this = (Type*) photo; \
+ return gst_camerasrc_photo_get_ ## function_name (this, param); \
+}
+
+
+#define GST_IMPLEMENT_CAMERA_SRC_PHOTO_METHODS(Type, interface_as_function) \
+ \
+GST_CAMERA_SRC_PHOTO_FUNCS(Type, interface_as_function, ev_compensation, gfloat) \
+GST_CAMERA_SRC_PHOTO_FUNCS(Type, interface_as_function, iso_speed, guint) \
+GST_CAMERA_SRC_PHOTO_FUNCS(Type, interface_as_function, aperture, guint) \
+GST_CAMERA_SRC_PHOTO_FUNCS(Type, interface_as_function, exposure, guint32) \
+GST_CAMERA_SRC_PHOTO_FUNCS(Type, interface_as_function, wb_mode, GstWhiteBalanceMode) \
+GST_CAMERA_SRC_PHOTO_FUNCS(Type, interface_as_function, tone_mode, GstColourToneMode) \
+GST_CAMERA_SRC_PHOTO_FUNCS(Type, interface_as_function, scene_mode, GstSceneMode) \
+GST_CAMERA_SRC_PHOTO_FUNCS(Type, interface_as_function, flash_mode, GstFlashMode) \
+GST_CAMERA_SRC_PHOTO_FUNCS(Type, interface_as_function, zoom, gint) \
+GST_CAMERA_SRC_PHOTO_FUNCS(Type, interface_as_function, flicker_mode, GstFlickerReductionMode) \
+GST_CAMERA_SRC_PHOTO_FUNCS(Type, interface_as_function, focus_mode, GstFocusMode) \
+ \
+GstPhotoCaps \
+interface_as_function ## _photo_get_capabilities (GstPhotography * photo) \
+{ \
+ Type *this = (Type*) photo; \
+ return gst_camerasrc_photo_get_capabilities (this); \
+} \
+ \
+gboolean \
+interface_as_function ## _photo_prepare_for_capture (GstPhotography * photo, \
+ GstPhotoCapturePrepared func, \
+ GstCaps *capture_caps, \
+ gpointer user_data) \
+{ \
+ Type *this = (Type*) photo; \
+ return gst_camerasrc_photo_prepare_for_capture (this, func, \
+ capture_caps, user_data); \
+} \
+ \
+void \
+interface_as_function ## _photo_set_autofocus (GstPhotography * photo, \
+ gboolean on) \
+{ \
+ Type *this = (Type*) photo; \
+ gst_camerasrc_photo_set_autofocus (this, on); \
+} \
+ \
+gboolean \
+interface_as_function ## _photo_set_config (GstPhotography * photo, \
+ GstPhotoSettings * config) \
+{ \
+ Type *this = (Type*) photo; \
+ return gst_camerasrc_photo_set_config (this, config); \
+} \
+ \
+gboolean \
+interface_as_function ## _photo_get_config (GstPhotography * photo, \
+ GstPhotoSettings * config) \
+{ \
+ Type *this = (Type*) photo; \
+ return gst_camerasrc_photo_get_config (this, config); \
+} \
+ \
+gboolean \
+interface_as_function ## _photo_set_format (GstPhotography * photo, \
+ GstOperationMode op_mode, \
+ GstCaps * op_mode_caps) \
+{ \
+ Type *this = (Type*) photo; \
+ return gst_camerasrc_photo_set_format (this, op_mode, op_mode_caps); \
+} \
+ \
+GstCaps * \
+interface_as_function ## _photo_get_format (GstPhotography * photo, \
+ GstOperationMode op_mode) \
+{ \
+ Type *this = (Type*) photo; \
+ return gst_camerasrc_photo_get_format (this, op_mode); \
+} \
+ \
+void \
+interface_as_function ## _photo_interface_init (GstPhotographyInterface * iface) \
+{ \
+ iface->set_ev_compensation = interface_as_function ## _photo_set_ev_compensation; \
+ iface->get_ev_compensation = interface_as_function ## _photo_get_ev_compensation; \
+ iface->set_iso_speed = interface_as_function ## _photo_set_iso_speed; \
+ iface->get_iso_speed = interface_as_function ## _photo_get_iso_speed; \
+ iface->set_aperture = interface_as_function ## _photo_set_aperture; \
+ iface->get_aperture = interface_as_function ## _photo_get_aperture; \
+ iface->set_exposure = interface_as_function ## _photo_set_exposure; \
+ iface->get_exposure = interface_as_function ## _photo_get_exposure; \
+ iface->set_white_balance_mode = interface_as_function ## _photo_set_wb_mode; \
+ iface->get_white_balance_mode = interface_as_function ## _photo_get_wb_mode; \
+ iface->set_colour_tone_mode = interface_as_function ## _photo_set_tone_mode; \
+ iface->get_colour_tone_mode = interface_as_function ## _photo_get_tone_mode; \
+ iface->set_scene_mode = interface_as_function ## _photo_set_scene_mode; \
+ iface->get_scene_mode = interface_as_function ## _photo_get_scene_mode; \
+ iface->set_flash_mode = interface_as_function ## _photo_set_flash_mode; \
+ iface->get_flash_mode = interface_as_function ## _photo_get_flash_mode; \
+ iface->set_zoom = interface_as_function ## _photo_set_zoom; \
+ iface->get_zoom = interface_as_function ## _photo_get_zoom; \
+ iface->set_flicker_mode = interface_as_function ## _photo_set_flicker_mode; \
+ iface->get_flicker_mode = interface_as_function ## _photo_get_flicker_mode; \
+ iface->set_focus_mode = interface_as_function ## _photo_set_focus_mode; \
+ iface->get_focus_mode = interface_as_function ## _photo_get_focus_mode; \
+ iface->set_config = interface_as_function ## _photo_set_config; \
+ iface->get_config = interface_as_function ## _photo_get_config; \
+ iface->set_format = interface_as_function ## _photo_set_format; \
+ iface->get_format = interface_as_function ## _photo_get_format; \
+ \
+ iface->get_capabilities = interface_as_function ## _photo_get_capabilities; \
+ iface->prepare_for_capture = interface_as_function ## _photo_prepare_for_capture; \
+ iface->set_autofocus = interface_as_function ## _photo_set_autofocus; \
+} \
+
+
+#endif /* __GST_CAMERA_SRC_PHOTOGRAPHY_H__ */
--- /dev/null
+/* GStreamer
+ *
+ * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * 2006 Edgard Lima <edgard.lima@indt.org.br>
+ * 2008-2010 Nokia Corporation <multimedia@maemo.org>
+ *
+ * gstcamerasrc.c: Abstract camera base class
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:gstcamerasrc
+ * @short_description: Base class for camera sources
+ *
+ * <refsect2>
+ * camerasrc is a generic base class for video source elements.
+ * </refsect2>
+ * <refsect2>
+ * <title>Capturing modes</title>
+ * <para>
+ * GstCameraSrc provides three different operating modes: VIEWFINDER, IMAGE and
+ * VIDEO capturing. This mode is selected by using "capture-mode" property.
+ * Viewfinder mode is used for capturing preview frames before performing the
+ * high-quality image capture, or before starting video recording. Image and
+ * video modes should be switched just before starting the corresponding
+ * action. GstCameraSrc itself doesn't make any difference between these modes,
+ * and this setting is mainly targeted for subclasses (see below).
+ * </para>
+ * </refsect2>
+ * <refsect2>
+ * <title>Image capture</title>
+ * <para>
+ * In order to capture and image of higher quality than negotiated in element's
+ * source pad, #GstPhotography's prepare_for_capture() must be called. It
+ * Takes a #GstCaps object as a parameter. These caps will define the desired
+ * high-quality capture resolution. However, this resolution is just a
+ * suggestion; GstCameraSrc uses the given #GstPhotoCapturePrepared callback
+ * to inform the selected capturing resolution back to the application. During
+ * this callback application also has responsibility to adjust image pipeline
+ * capsfilters according to this resolution. After HQ image is captured and
+ * pushed, GstCameraSrc switches automatically back to old viewfinder resolution.
+ * </para>
+ * </refsect2>
+ * <refsect2>
+ * <title>Video capture</title>
+ * <para>
+ * By default GstCameraSrc works just like v4l2src, so it can be used for normal
+ * video stream capturing as well. There is no separate GstPhotography API
+ * function for starting video capturing (in contrary to image capturing), but
+ * the notification is just given by setting the #GstCameraSrc:capture-mode
+ * to video.
+ * </para>
+ * </refsect2>
+ * <refsect2>
+ * <title>Messages</title>
+ * <para>
+ * During capturing process GstCameraSrc sends a bunch of GstMessages to bus:
+ * <itemizedlist>
+ * <listitem>
+ * <para>
+ * GST_PHOTOGRAPHY_AUTOFOCUS_DONE is sent when application has started
+ * autofocus operation and it finishes. This message contains following fields:
+ * "status" tells whether the focusing succeeded or failed.
+ * "focus_window_rows" and "focus_window_columns" tell the focus matrix size.
+ * "focus_window_mask" is an integer containing a bitmask. It contains
+ * rows x columns bits, which mark the focus points in the focus matrix.
+ * Lowest bit (LSB) always represents the top-left corner of the focus matrix.
+ * This field is only valid when focusing status is SUCCESS.
+ * </para>
+ * </listitem>
+ * <listitem>
+ * <para>
+ * GST_PHOTOGRAPHY_SHAKE_RISK is sent during autofocusing process. It keeps
+ * application updated about the possible risk for shaken image.
+ * </para>
+ * </listitem>
+ * <listitem>
+ * <para>
+ * "photo-capture-start" is sent just before the actual high-quality capture
+ * operation is about to happen.
+ * </para>
+ * </listitem>
+ * <listitem>
+ * <para>
+ * "photo-capture-end" is sent immediately after high-quality image has been
+ * captured. This can be used for example for playing the shutter sound
+ * in sync with the capture operation.
+ * </para>
+ * </listitem>
+ * <listitem>
+ * <para>
+ * "caf-update" messages are sent when camera subsystem supports continuous
+ * autofocusing (CAF). The message contains information about CAF status. It
+ * has one G_TYPE_INT field called "status" and it may contain following values:
+ * 0 - IDLE, 1 - RUNNING, 2 - SUCCESS, 3 - FAILURE.
+ * </para>
+ * </listitem>
+ * </itemizedlist>
+ * </para>
+ * </refsect2>
+ * <refsect2>
+ * <title>Supported formats</title>
+ * <para>
+ * Currently GstCameraSrc only supports UYVY and YUY2 color formats.
+ * </para>
+ * </refsect2>
+ * <refsect2>
+ * <title>Subclasses</title>
+ * <para>
+ * Hardware-specific imaging functionalities are implemented in subclasses.
+ * GstCameraSrc provides vmethods for this purpose. Subclasses tasks are to
+ * are handle e.g. autofocusing, flash, image capturing,
+ * post-processing and all other non-V4L2 standard operations. Subclass
+ * can also implement the API only partially; by default GstCameraSrc uses dummy
+ * functions for all vmethods that are not implemented by the subclass.
+ * </para>
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <gst/tag/tag.h>
+
+#include "gstcameracolorbalance.h"
+#include "gstcameraphotoiface.h"
+
+
+GST_DEBUG_CATEGORY (gst_camerasrc_debug);
+#define GST_CAT_DEFAULT gst_camerasrc_debug
+
+
+#define DEFAULT_PROP_ALWAYS_COPY FALSE
+
+#define MIN_ZOOM 0.0
+#define MAX_ZOOM 1000.0
+#define ZOOM_1X 100.0
+
+GST_IMPLEMENT_CAMERA_SRC_COLOR_BALANCE_METHODS (GstCameraSrc, gst_camsrc);
+GST_IMPLEMENT_CAMERA_SRC_PHOTO_METHODS (GstCameraSrc, gst_camsrc);
+
+static gboolean
+gst_camerasrc_iface_supported (GstImplementsInterface * iface, GType iface_type)
+{
+ GstCameraSrc *camsrc;
+ GstCameraSrcClass *bclass;
+
+ camsrc = GST_CAMERA_SRC (iface);
+ bclass = GST_CAMERA_SRC_GET_CLASS (camsrc);
+
+ g_assert (iface_type == GST_TYPE_PHOTOGRAPHY ||
+ iface_type == GST_TYPE_COLOR_BALANCE);
+
+ /* We implement GstPhotography in NULL state as well */
+ if (iface_type == GST_TYPE_PHOTOGRAPHY)
+ return TRUE;
+
+ else if (!bclass->is_open (camsrc))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+gst_camerasrc_interface_init (GstImplementsInterfaceClass * klass)
+{
+ /*
+ * default virtual functions
+ */
+ klass->supported = gst_camerasrc_iface_supported;
+}
+
+void
+gst_camerasrc_init_interfaces (GType type)
+{
+ static const GInterfaceInfo camsrc_iface_info = {
+ (GInterfaceInitFunc) gst_camerasrc_interface_init,
+ NULL,
+ NULL,
+ };
+ static const GInterfaceInfo camsrc_photo_info = {
+ (GInterfaceInitFunc) gst_camsrc_photo_interface_init,
+ NULL,
+ NULL,
+ };
+ static const GInterfaceInfo camsrc_colorbalance_info = {
+ (GInterfaceInitFunc) gst_camsrc_color_balance_interface_init,
+ NULL,
+ NULL,
+ };
+
+ g_type_add_interface_static (type,
+ GST_TYPE_IMPLEMENTS_INTERFACE, &camsrc_iface_info);
+ g_type_add_interface_static (type,
+ GST_TYPE_PHOTOGRAPHY, &camsrc_photo_info);
+ g_type_add_interface_static (type,
+ GST_TYPE_COLOR_BALANCE, &camsrc_colorbalance_info);
+}
+
+
+GType
+gst_camerasrc_capture_mode_get_type (void)
+{
+ static GType gst_camerasrc_capture_mode_type = 0;
+ static GEnumValue gst_camerasrc_capture_modes[] = {
+ {GST_CAMERA_SRC_CAPTURE_MODE_VIEWFINDER, "Viewfinder mode", "viewfinder"},
+ {GST_CAMERA_SRC_CAPTURE_MODE_STILL, "Still image capture mode", "still"},
+ {GST_CAMERA_SRC_CAPTURE_MODE_VIDEO, "Video capturing mode", "video"},
+ {0, NULL, NULL},
+ };
+
+ if (G_UNLIKELY (!gst_camerasrc_capture_mode_type)) {
+ gst_camerasrc_capture_mode_type =
+ g_enum_register_static ("GstCameraCaptureMode",
+ gst_camerasrc_capture_modes);
+ }
+ return gst_camerasrc_capture_mode_type;
+}
+
+GType
+gst_camerasrc_viewfinder_mode_get_type (void)
+{
+ static GType gst_camerasrc_viewfinder_mode_type = 0;
+ static GEnumValue gst_camerasrc_viewfinder_modes[] = {
+ {GST_CAMERA_SRC_VIEWFINDER_MODE_STILL, "Still image capture mode", "still"},
+ {GST_CAMERA_SRC_VIEWFINDER_MODE_VIDEO, "Video capturing mode", "video"},
+ {0, NULL, NULL},
+ };
+
+ if (G_UNLIKELY (!gst_camerasrc_viewfinder_mode_type)) {
+ gst_camerasrc_viewfinder_mode_type =
+ g_enum_register_static ("GstCameraViewfinderMode",
+ gst_camerasrc_viewfinder_modes);
+ }
+ return gst_camerasrc_viewfinder_mode_type;
+}
+
+GST_BOILERPLATE_FULL (GstCameraSrc, gst_camerasrc, GstPushSrc,
+ GST_TYPE_PUSH_SRC, gst_camerasrc_init_interfaces);
+
+static void gst_camerasrc_dispose (GObject * object);
+
+/* element methods */
+static GstStateChangeReturn
+gst_camerasrc_change_state (GstElement * element, GstStateChange transition);
+
+/* basesrc methods */
+static gboolean gst_camerasrc_start (GstBaseSrc * src);
+
+static gboolean gst_camerasrc_unlock (GstBaseSrc * src);
+
+static gboolean gst_camerasrc_unlock_stop (GstBaseSrc * src);
+
+static gboolean gst_camerasrc_stop (GstBaseSrc * src);
+
+static gboolean gst_camerasrc_set_caps (GstBaseSrc * src, GstCaps * caps);
+
+static GstCaps *gst_camerasrc_get_caps (GstBaseSrc * src);
+
+static gboolean gst_camerasrc_query (GstBaseSrc * bsrc, GstQuery * query);
+
+static GstFlowReturn gst_camerasrc_create (GstPushSrc * src, GstBuffer ** out);
+
+static void gst_camerasrc_fixate (GstBaseSrc * basesrc, GstCaps * caps);
+
+static gboolean gst_camerasrc_negotiate (GstBaseSrc * basesrc);
+
+static void gst_camerasrc_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+
+static void gst_camerasrc_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void gst_camerasrc_override_photo_properties (
+ GObjectClass *gobject_class);
+
+static void gst_camerasrc_default_functions_init (
+ GstCameraSrcClass *camera_class);
+
+static gboolean gst_camerasrc_event (GstBaseSrc * src, GstEvent * event);
+
+static gboolean gst_camerasrc_send_event (GstElement * element,
+ GstEvent * event);
+
+static void gst_camerasrc_update_max_zoom (GstCameraSrc *camerasrc);
+
+/*
+ */
+static void
+gst_camerasrc_base_init (gpointer g_class)
+{
+// GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
+ gst_tag_register_musicbrainz_tags ();
+
+ GST_DEBUG_CATEGORY_INIT (gst_camerasrc_debug, "camerasrc", 0,
+ "camerasrc element");
+}
+
+/*
+ */
+static void
+gst_camerasrc_class_init (GstCameraSrcClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *element_class;
+ GstBaseSrcClass *basesrc_class;
+ GstPushSrcClass *pushsrc_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ element_class = GST_ELEMENT_CLASS (klass);
+ basesrc_class = GST_BASE_SRC_CLASS (klass);
+ pushsrc_class = GST_PUSH_SRC_CLASS (klass);
+
+ gobject_class->dispose = gst_camerasrc_dispose;
+ gobject_class->set_property = gst_camerasrc_set_property;
+ gobject_class->get_property = gst_camerasrc_get_property;
+
+ element_class->change_state = gst_camerasrc_change_state;
+ element_class->send_event = gst_camerasrc_send_event;
+
+ g_object_class_install_property (gobject_class, PROP_ALWAYS_COPY,
+ g_param_spec_boolean ("always-copy", "Always Copy",
+ "If the buffer will or not be used directly from mmap",
+ DEFAULT_PROP_ALWAYS_COPY, G_PARAM_READWRITE));
+
+ /**
+ * GstCameraSrc:capture-mode:
+ *
+ * Defines capturing mode to be used. This information is needed by extension
+ * modules, which control hardware-specific functionality.
+ */
+ g_object_class_install_property (gobject_class, PROP_CAPTURE_MODE,
+ g_param_spec_enum ("capture-mode", "Capturing mode",
+ "Defines what kind of capturing mode to be used",
+ GST_TYPE_CAMERA_SRC_CAPTURE_MODE,
+ GST_CAMERA_SRC_CAPTURE_MODE_VIEWFINDER,
+ G_PARAM_READWRITE));
+
+ /**
+ * GstCameraSrc:viewfinder-mode:
+ *
+ * Defines which mode viewfinder should run in. This information is needed
+ * by extension modules, which control hardware-specific functionality.
+ */
+ g_object_class_install_property (gobject_class, PROP_VIEWFINDER_MODE,
+ g_param_spec_enum ("viewfinder-mode", "Viewfinder mode",
+ "Defines in what mode viewfinder should be run",
+ GST_TYPE_CAMERA_SRC_VIEWFINDER_MODE,
+ GST_CAMERA_SRC_VIEWFINDER_MODE_STILL,
+ G_PARAM_READWRITE));
+
+ gst_camerasrc_override_photo_properties (gobject_class);
+
+ basesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_camerasrc_get_caps);
+ basesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_camerasrc_set_caps);
+ basesrc_class->start = GST_DEBUG_FUNCPTR (gst_camerasrc_start);
+ basesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_camerasrc_unlock);
+ basesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_camerasrc_unlock_stop);
+ basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_camerasrc_stop);
+ basesrc_class->query = GST_DEBUG_FUNCPTR (gst_camerasrc_query);
+ basesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_camerasrc_fixate);
+ basesrc_class->negotiate = GST_DEBUG_FUNCPTR (gst_camerasrc_negotiate);
+ basesrc_class->event = GST_DEBUG_FUNCPTR (gst_camerasrc_event);
+
+ pushsrc_class->create = GST_DEBUG_FUNCPTR (gst_camerasrc_create);
+
+ /* Initialize vmethods with default implementations */
+ gst_camerasrc_default_functions_init (klass);
+}
+
+/*
+ */
+static void
+gst_camerasrc_init (GstCameraSrc * camerasrc, GstCameraSrcClass * klass)
+{
+ /* number of buffers requested */
+ camerasrc->always_copy = DEFAULT_PROP_ALWAYS_COPY;
+
+ camerasrc->state_lock = g_mutex_new ();
+ camerasrc->af_lock = g_mutex_new ();
+
+ gst_base_src_set_format (GST_BASE_SRC (camerasrc), GST_FORMAT_TIME);
+ gst_base_src_set_live (GST_BASE_SRC (camerasrc), TRUE);
+
+ /* Photo interface */
+ camerasrc->photoconf.zoom = 100;
+ camerasrc->photoconf.ev_compensation = 0.0;
+ camerasrc->photoconf.exposure = 0; /* 0 = auto */
+ camerasrc->photoconf.aperture = 0; /* 0 = auto */
+ camerasrc->photoconf.iso_speed = 0; /* 0 = auto */
+ camerasrc->photoconf.wb_mode = GST_PHOTOGRAPHY_WB_MODE_AUTO;
+ camerasrc->photoconf.scene_mode = GST_PHOTOGRAPHY_SCENE_MODE_MANUAL;
+ camerasrc->photoconf.flash_mode = GST_PHOTOGRAPHY_FLASH_MODE_AUTO;
+ camerasrc->photoconf.tone_mode = GST_PHOTOGRAPHY_COLOUR_TONE_MODE_NORMAL;
+ camerasrc->photoconf.flicker_mode = GST_PHOTOGRAPHY_FLICKER_REDUCTION_OFF;
+ camerasrc->photoconf.focus_mode = GST_PHOTOGRAPHY_FOCUS_MODE_AUTO;
+
+ camerasrc->photo_capture_phase = GST_CAMERA_VIEWFINDER;
+ camerasrc->capture_mode = GST_CAMERA_SRC_CAPTURE_MODE_VIEWFINDER;
+ camerasrc->viewfinder_mode = GST_CAMERA_SRC_VIEWFINDER_MODE_STILL;
+ camerasrc->capture_resolution_set = FALSE;
+ camerasrc->preview_resolution_set = FALSE;
+
+ camerasrc->capture_w = 0;
+ camerasrc->capture_h = 0;
+ camerasrc->capture_fps_n = 0;
+ camerasrc->capture_fps_d = 0;
+ camerasrc->capture_fourcc = 0;
+
+ camerasrc->preview_w = 0;
+ camerasrc->preview_h = 0;
+ camerasrc->preview_fourcc = 0;
+
+ camerasrc->requested_af_mode = AF_NONE_REQUESTED;
+}
+
+/*
+ */
+static void
+gst_camerasrc_dispose (GObject * object)
+{
+ GstCameraSrc *camerasrc = GST_CAMERA_SRC_CAST (object);
+
+ if (camerasrc->vf_caps) {
+ gst_caps_unref (camerasrc->vf_caps);
+ camerasrc->vf_caps = NULL;
+ }
+ if (camerasrc->state_lock) {
+ g_mutex_free (camerasrc->state_lock);
+ camerasrc->state_lock = NULL;
+ }
+ if (camerasrc->af_lock) {
+ g_mutex_free (camerasrc->af_lock);
+ camerasrc->af_lock = NULL;
+ }
+ gst_camerasrc_clear_color_channels (camerasrc);
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_camerasrc_override_photo_properties (GObjectClass *gobject_class)
+{
+ g_object_class_override_property (gobject_class, PROP_WB_MODE,
+ GST_PHOTOGRAPHY_PROP_WB_MODE);
+
+ g_object_class_override_property (gobject_class, PROP_COLOUR_TONE,
+ GST_PHOTOGRAPHY_PROP_COLOUR_TONE);
+
+ g_object_class_override_property (gobject_class, PROP_SCENE_MODE,
+ GST_PHOTOGRAPHY_PROP_SCENE_MODE);
+
+ g_object_class_override_property (gobject_class, PROP_FLASH_MODE,
+ GST_PHOTOGRAPHY_PROP_FLASH_MODE);
+
+ g_object_class_override_property (gobject_class, PROP_CAPABILITIES,
+ GST_PHOTOGRAPHY_PROP_CAPABILITIES);
+
+ g_object_class_override_property (gobject_class, PROP_EV_COMP,
+ GST_PHOTOGRAPHY_PROP_EV_COMP);
+
+ g_object_class_override_property (gobject_class, PROP_ISO_SPEED,
+ GST_PHOTOGRAPHY_PROP_ISO_SPEED);
+
+ g_object_class_override_property (gobject_class, PROP_APERTURE,
+ GST_PHOTOGRAPHY_PROP_APERTURE);
+
+ g_object_class_override_property (gobject_class, PROP_EXPOSURE,
+ GST_PHOTOGRAPHY_PROP_EXPOSURE);
+
+ g_object_class_override_property (gobject_class, PROP_ZOOM,
+ GST_PHOTOGRAPHY_PROP_ZOOM);
+
+ g_object_class_override_property (gobject_class, PROP_FLICKER_MODE,
+ GST_PHOTOGRAPHY_PROP_FLICKER_MODE);
+
+ g_object_class_override_property (gobject_class, PROP_FOCUS_MODE,
+ GST_PHOTOGRAPHY_PROP_FOCUS_MODE);
+
+ g_object_class_override_property (gobject_class, PROP_IMAGE_CAPTURE_CAPS,
+ GST_PHOTOGRAPHY_PROP_IMAGE_CAPTURE_SUPPORTED_CAPS);
+
+ g_object_class_override_property (gobject_class, PROP_IMAGE_PREVIEW_CAPS,
+ GST_PHOTOGRAPHY_PROP_IMAGE_PREVIEW_SUPPORTED_CAPS);
+
+ g_object_class_override_property (gobject_class, PROP_AUTOFOCUS,
+ GST_PHOTOGRAPHY_PROP_AUTOFOCUS);
+}
+
+
+/*
+ */
+static void
+gst_camerasrc_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ GstCameraSrc *camerasrc;
+ GstCameraSrcClass *bclass;
+
+ camerasrc = GST_CAMERA_SRC_CAST (object);
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ if (gst_camerasrc_photo_set_property (camerasrc, prop_id, value))
+ return;
+
+ switch (prop_id) {
+ case PROP_ALWAYS_COPY:
+ camerasrc->always_copy = g_value_get_boolean (value);
+ break;
+ case PROP_CAPTURE_MODE:
+ camerasrc->capture_mode = g_value_get_enum (value);
+ GST_INFO_OBJECT (camerasrc, "Setting capture mode: %d",
+ camerasrc->capture_mode);
+
+ if (camerasrc->capture_mode == GST_CAMERA_SRC_CAPTURE_MODE_VIDEO &&
+ bclass->is_active (camerasrc))
+ {
+ /* Stop autofocus in video mode */
+ bclass->set_autofocus (camerasrc, FALSE);
+ /* AutoExposure must be run always in video mode */
+ bclass->set_autoexposure (camerasrc, TRUE);
+ }
+ if (bclass->set_capture_mode) {
+ bclass->set_capture_mode (camerasrc, camerasrc->capture_mode);
+ }
+ break;
+
+ case PROP_VIEWFINDER_MODE:
+ camerasrc->viewfinder_mode = g_value_get_enum (value);
+ GST_INFO_OBJECT (camerasrc, "Setting viewfinder mode: %d",
+ camerasrc->viewfinder_mode);
+
+ if (bclass->set_vfinder_mode) {
+ bclass->set_vfinder_mode (camerasrc, camerasrc->viewfinder_mode);
+ }
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/*
+ */
+static void
+gst_camerasrc_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ GstCameraSrc *camerasrc = GST_CAMERA_SRC_CAST (object);
+
+ if (gst_camerasrc_photo_get_property (camerasrc, prop_id, value))
+ return;
+
+ switch (prop_id) {
+ case PROP_ALWAYS_COPY:
+ g_value_set_boolean (value, camerasrc->always_copy);
+ break;
+ case PROP_CAPTURE_MODE:
+ g_value_set_enum (value, camerasrc->capture_mode);
+ break;
+ case PROP_VIEWFINDER_MODE:
+ g_value_set_enum (value, camerasrc->viewfinder_mode);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/* this function is a bit of a last resort */
+static void
+gst_camerasrc_fixate (GstBaseSrc * basesrc, GstCaps * caps)
+{
+ GstStructure *structure;
+
+ gint i;
+
+ GST_DEBUG_OBJECT (basesrc, "fixating caps %" GST_PTR_FORMAT, caps);
+
+ for (i = 0; i < gst_caps_get_size (caps); ++i) {
+ const GValue *v;
+
+ structure = gst_caps_get_structure (caps, i);
+
+ /* FIXME such sizes? we usually fixate to something in the 320x200
+ * range... */
+ /* We are fixating to greatest possble size (limited to GST_CAMERA_SRC_MAX_SIZE)
+ and the maximum framerate resolution for that size */
+ gst_structure_fixate_field_nearest_int (structure, "width",
+ GST_CAMERA_SRC_MAX_SIZE);
+ gst_structure_fixate_field_nearest_int (structure, "height",
+ GST_CAMERA_SRC_MAX_SIZE);
+ gst_structure_fixate_field_nearest_fraction (structure, "framerate",
+ G_MAXINT, 1);
+
+ v = gst_structure_get_value (structure, "format");
+ if (v && G_VALUE_TYPE (v) != GST_TYPE_FOURCC) {
+ guint32 fourcc;
+
+ g_return_if_fail (G_VALUE_TYPE (v) == GST_TYPE_LIST);
+
+ fourcc = gst_value_get_fourcc (gst_value_list_get_value (v, 0));
+ gst_structure_set (structure, "format", GST_TYPE_FOURCC, fourcc, NULL);
+ }
+ }
+
+ GST_DEBUG_OBJECT (basesrc, "fixated caps %" GST_PTR_FORMAT, caps);
+}
+
+/*
+ */
+static gboolean
+gst_camerasrc_negotiate (GstBaseSrc * basesrc)
+{
+ GstCaps *thiscaps;
+
+ GstCaps *caps = NULL;
+
+ GstCaps *peercaps = NULL;
+
+ gboolean result = FALSE;
+
+ /* first see what is possible on our source pad */
+ thiscaps = gst_pad_get_caps (GST_BASE_SRC_PAD (basesrc));
+ GST_DEBUG_OBJECT (basesrc, "caps of src: %" GST_PTR_FORMAT, thiscaps);
+ /* nothing or anything is allowed, we're done */
+ if (thiscaps == NULL || gst_caps_is_any (thiscaps))
+ goto no_nego_needed;
+
+ /* get the peer caps */
+ peercaps = gst_pad_peer_get_caps (GST_BASE_SRC_PAD (basesrc));
+ GST_DEBUG_OBJECT (basesrc, "caps of peer: %" GST_PTR_FORMAT, peercaps);
+ if (peercaps && !gst_caps_is_any (peercaps)) {
+ GstCaps *icaps = NULL;
+ int i;
+
+ /* Prefer the first caps we are compatible with that the peer proposed */
+ for (i = 0; i < gst_caps_get_size (peercaps); i++) {
+ /* get intersection */
+ GstCaps *ipcaps = gst_caps_copy_nth (peercaps, i);
+
+ GST_DEBUG_OBJECT (basesrc, "peer: %" GST_PTR_FORMAT, ipcaps);
+
+ icaps = gst_caps_intersect (thiscaps, ipcaps);
+ gst_caps_unref (ipcaps);
+
+ if (!gst_caps_is_empty (icaps))
+ break;
+
+ gst_caps_unref (icaps);
+ icaps = NULL;
+ }
+
+ GST_DEBUG_OBJECT (basesrc, "intersect: %" GST_PTR_FORMAT, icaps);
+ if (icaps) {
+ /* If there are multiple intersections pick the one with the smallest
+ * resolution strictly bigger then the first peer caps */
+ if (gst_caps_get_size (icaps) > 1) {
+ GstStructure *s = gst_caps_get_structure (peercaps, 0);
+
+ int best = 0;
+
+ int twidth, theight;
+
+ int width = G_MAXINT, height = G_MAXINT;
+
+ if (gst_structure_get_int (s, "width", &twidth)
+ && gst_structure_get_int (s, "height", &theight)) {
+
+ /* Walk the structure backwards to get the first entry of the
+ * smallest resolution bigger (or equal to) the preferred resolution)
+ */
+ for (i = gst_caps_get_size (icaps) - 1; i >= 0; i--) {
+ GstStructure *is = gst_caps_get_structure (icaps, i);
+
+ int w, h;
+
+ if (gst_structure_get_int (is, "width", &w)
+ && gst_structure_get_int (is, "height", &h)) {
+ if (w >= twidth && w <= width && h >= theight && h <= height) {
+ width = w;
+ height = h;
+ best = i;
+ }
+ }
+ }
+ }
+
+ caps = gst_caps_copy_nth (icaps, best);
+ gst_caps_unref (icaps);
+ } else {
+ caps = icaps;
+ }
+ }
+ gst_caps_unref (thiscaps);
+ gst_caps_unref (peercaps);
+ } else {
+ /* no peer or peer have ANY caps, work with our own caps then */
+ caps = thiscaps;
+ }
+ if (caps) {
+ caps = gst_caps_make_writable (caps);
+ gst_caps_truncate (caps);
+
+ /* now fixate */
+ if (!gst_caps_is_empty (caps)) {
+ gst_pad_fixate_caps (GST_BASE_SRC_PAD (basesrc), caps);
+ GST_DEBUG_OBJECT (basesrc, "fixated to: %" GST_PTR_FORMAT, caps);
+
+ if (gst_caps_is_any (caps)) {
+ /* hmm, still anything, so element can do anything and
+ * nego is not needed */
+ result = TRUE;
+ } else if (gst_caps_is_fixed (caps)) {
+ /* yay, fixed caps, use those then */
+ result = gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), caps);
+ GST_DEBUG_OBJECT (basesrc, "Set caps returned: %d", result);
+ }
+ }
+ gst_caps_unref (caps);
+ }
+ return result;
+
+no_nego_needed:
+ {
+ GST_DEBUG_OBJECT (basesrc, "no negotiation needed");
+ if (thiscaps)
+ gst_caps_unref (thiscaps);
+ return TRUE;
+ }
+}
+
+
+/*
+ */
+static GstCaps *
+gst_camerasrc_get_caps (GstBaseSrc * src)
+{
+ GstCameraSrc *camerasrc;
+ GstCameraSrcClass *bclass;
+
+ camerasrc = GST_CAMERA_SRC_CAST (src);
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ if (!bclass->is_open (camerasrc) || !bclass->get_caps) {
+ return gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD
+ (camerasrc)));
+ }
+
+ return bclass->get_caps (camerasrc);
+}
+
+
+/**
+ * gst_camerasrc_get_caps_info:
+ * @caps: given input caps
+ * @four_cc: location for the fourcc
+ * @w/@h: location for width and height
+ * @fps_n/@fps_d: location for framerate
+ *
+ * Collect data for the given caps.
+ */
+static gboolean
+gst_camerasrc_get_caps_info (GstCameraSrc * camerasrc, GstCaps * caps,
+ guint32 *four_cc, guint * w, guint * h, guint * fps_n, guint * fps_d)
+{
+ GstCameraSrcClass *bclass;
+ GstStructure *structure;
+ const GValue *framerate;
+ const gchar *mimetype;
+ guint32 fourcc;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ /* default unknown values */
+ fourcc = 0;
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ mimetype = gst_structure_get_name (structure);
+
+ if (!gst_structure_get_int (structure, "width", (gint *) w))
+ return FALSE;
+
+ if (!gst_structure_get_int (structure, "height", (gint *) h))
+ return FALSE;
+
+ framerate = gst_structure_get_value (structure, "framerate");
+ if (!framerate)
+ return FALSE;
+
+ *fps_n = gst_value_get_fraction_numerator (framerate);
+ *fps_d = gst_value_get_fraction_denominator (framerate);
+
+ if(!strcmp(mimetype, "video/x-raw-yuv")) {
+ gst_structure_get_fourcc (structure, "format", &fourcc);
+
+ switch (fourcc) {
+ case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
+ fourcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', 'V');
+ break;
+ case GST_MAKE_FOURCC ('I', '4', '2', '0'):
+ fourcc = GST_MAKE_FOURCC('Y', 'U', '1', '2');
+ break;
+ default:
+ fourcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
+ break;
+ }
+ }
+
+ if (!strcmp(mimetype, "video/x-raw-bayer"))
+ fourcc = GST_MAKE_FOURCC('B', 'A', '8', '1');
+
+ *four_cc = fourcc;
+
+ return TRUE;
+}
+
+
+/**
+ * gst_camerasrc_get_caps_from_info:
+ * @camsrc: #GstCameraSrc object
+ * @fourcc: fourcc code
+ * @width: width to be set
+ * @height: height to be set
+ * @fps_n: FPS numerator to be set or 0
+ * @fps_d: FPS denominator to be set or 0
+ *
+ * Converts given parameters into GstCaps structure.
+ *
+ * Returns: GstCaps representing the given values.
+ */
+GstCaps *
+gst_camerasrc_get_caps_from_info (GstCameraSrc *camsrc, guint32 fourcc,
+ guint width, guint height, guint fps_n, guint fps_d)
+{
+ GstCaps *newcaps;
+ GstStructure *s;
+
+ s = gst_structure_new ("video/x-raw-yuv",
+ "format", GST_TYPE_FOURCC, fourcc,
+ "width", G_TYPE_INT, width,
+ "height", G_TYPE_INT, height,
+ NULL);
+
+ if (fps_n != 0 && fps_d != 0) {
+ gst_structure_set (s, "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
+ }
+
+ newcaps = gst_caps_new_empty ();
+ gst_caps_append_structure (newcaps, s);
+
+ return newcaps;
+}
+
+
+/*
+ */
+static gboolean
+gst_camerasrc_configure_device (GstCameraSrc *camerasrc, guint *w, guint *h,
+ guint32 *fourcc, guint *fps_n, guint *fps_d, GstCaps *buffer_caps)
+{
+ GstCameraSrcClass *bclass;
+ GstOperationMode opmode;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ /* Stop the capturing */
+ if (!bclass->stop (camerasrc))
+ return FALSE;
+
+ GST_DEBUG_OBJECT (camerasrc, "trying to set_capture %dx%d at %d/%d fps",
+ *w, *h, *fps_n, *fps_d);
+
+ if (bclass->set_vfinder_mode) {
+ bclass->set_vfinder_mode (camerasrc, camerasrc->viewfinder_mode);
+ }
+ if (bclass->set_capture_mode) {
+ bclass->set_capture_mode (camerasrc, camerasrc->capture_mode);
+ }
+
+ opmode = camerasrc->photo_capture_phase == GST_CAMERA_CAPTURE ?
+ GST_PHOTOGRAPHY_OPERATION_MODE_IMAGE_CAPTURE :
+ GST_PHOTOGRAPHY_OPERATION_MODE_VIEWFINDER;
+
+ if (!bclass->set_capture (camerasrc, opmode, FALSE, fourcc, w, h,
+ fps_n, fps_d))
+ {
+ GST_ELEMENT_ERROR (camerasrc, RESOURCE, SETTINGS,
+ ("Failed configuring device for capturing"), (NULL));
+ return FALSE;
+ }
+
+ gst_camerasrc_update_max_zoom (camerasrc);
+
+ /* Only start the driver when not in HQ capture mode, since in HQ mode */
+ /* we have already called start_capture() above */
+ if (camerasrc->photo_capture_phase != GST_CAMERA_CAPTURE) {
+
+ if (!bclass->write_settings (camerasrc, &camerasrc->photoconf, FALSE)) {
+ GST_ELEMENT_ERROR (camerasrc, RESOURCE, SETTINGS,
+ ("Failed to configure driver module"), (NULL));
+
+ return FALSE;
+ }
+ }
+
+ if (!bclass->start (camerasrc, buffer_caps))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/*
+ */
+static gboolean
+gst_camerasrc_init_from_caps (GstCameraSrc *camerasrc, GstCaps * caps)
+{
+ guint w = 0, h = 0;
+ guint32 fourcc;
+ guint fps_n, fps_d;
+ gboolean ret;
+
+ /* we want our own type of fourcc codes */
+ if (!gst_camerasrc_get_caps_info (camerasrc, caps, &fourcc, &w, &h, &fps_n,
+ &fps_d))
+ {
+ GST_DEBUG_OBJECT (camerasrc,
+ "can't get capture format from caps %" GST_PTR_FORMAT, caps);
+ return FALSE;
+ }
+
+ ret = gst_camerasrc_configure_device (camerasrc, &w, &h, &fourcc,
+ &fps_n, &fps_d, caps);
+
+ if (ret) {
+ camerasrc->current_w = w;
+ camerasrc->current_h = h;
+ camerasrc->fps_n = fps_n;
+ camerasrc->fps_d = fps_d;
+ camerasrc->current_fourcc = fourcc;
+ }
+
+ return ret;
+}
+
+/*
+ */
+static gboolean
+gst_camerasrc_set_caps (GstBaseSrc * src, GstCaps * caps)
+{
+ GstCameraSrc *camerasrc;
+ GstCameraSrcClass *bclass;
+
+ camerasrc = GST_CAMERA_SRC_CAST (src);
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ GST_DEBUG_OBJECT (camerasrc, "set_caps called: %" GST_PTR_FORMAT, caps);
+
+ /* if we're not open, punt -- we'll get setcaps'd later via negotiate */
+ if (!bclass->is_open (camerasrc))
+ return FALSE;
+
+ return gst_camerasrc_init_from_caps (camerasrc, caps);
+}
+
+/*
+ */
+static gboolean
+gst_camerasrc_query (GstBaseSrc * bsrc, GstQuery * query)
+{
+ GstCameraSrc *src;
+ GstCameraSrcClass *bclass;
+ gboolean res = FALSE;
+ guint num_buffers;
+
+ src = GST_CAMERA_SRC_CAST (bsrc);
+ bclass = GST_CAMERA_SRC_GET_CLASS (src);
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_LATENCY:{
+ GstClockTime min_latency, max_latency;
+
+ /* device must be open */
+ if (!bclass->is_open (src)) {
+ GST_WARNING_OBJECT (src, "Can't give latency since device isn't open !");
+ goto done;
+ }
+
+ /* we must have a framerate */
+ if (src->fps_n <= 0 || src->fps_d <= 0) {
+ GST_WARNING_OBJECT (src,
+ "Can't give latency since framerate isn't fixated !");
+ goto done;
+ }
+
+ /* min latency is the time to capture one frame */
+ min_latency =
+ gst_util_uint64_scale_int (GST_SECOND,
+ src->fps_d, src->fps_n);
+
+ num_buffers = bclass->get_num_buffers (src);
+ /* max latency is total duration of the frame buffer */
+ max_latency = num_buffers * min_latency;
+
+ GST_DEBUG_OBJECT (bsrc,
+ "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
+
+ /* we are always live, the min latency is 1 frame and the max latency is
+ * the complete buffer of frames. */
+ gst_query_set_latency (query, TRUE, min_latency, max_latency);
+
+ res = TRUE;
+ break;
+ }
+ default:
+ res = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
+ break;
+ }
+
+done:
+
+ return res;
+}
+
+static gboolean
+gst_camerasrc_start (GstBaseSrc * src)
+{
+// GstCameraSrc *camerasrc = GST_CAMERA_SRC_CAST (src);
+
+ return TRUE;
+}
+
+/*
+ */
+static gboolean
+gst_camerasrc_stop (GstBaseSrc * src)
+{
+ GstCameraSrc *camerasrc;
+ GstCameraSrcClass *bclass;
+
+ camerasrc = GST_CAMERA_SRC_CAST (src);
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ GST_DEBUG_OBJECT (camerasrc, "Stopping");
+
+ bclass->stop (camerasrc);
+
+ camerasrc->photo_capture_phase = GST_CAMERA_VIEWFINDER;
+
+ return TRUE;
+}
+
+static gboolean
+gst_camerasrc_unlock (GstBaseSrc * src)
+{
+ GstCameraSrcClass *pclass;
+ GstCameraSrc *camerasrc;
+ gboolean ret = TRUE;
+
+ camerasrc = GST_CAMERA_SRC_CAST (src);
+ pclass = GST_CAMERA_SRC_GET_CLASS (src);
+
+ GST_DEBUG_OBJECT (camerasrc, "Unlock");
+
+ if (pclass->unlock)
+ ret = pclass->unlock (camerasrc);
+
+ return ret;
+}
+
+static gboolean
+gst_camerasrc_unlock_stop (GstBaseSrc * src)
+{
+ GstCameraSrcClass *pclass;
+ GstCameraSrc *camerasrc;
+ gboolean ret = TRUE;
+
+ camerasrc = GST_CAMERA_SRC_CAST (src);
+ pclass = GST_CAMERA_SRC_GET_CLASS (src);
+
+ GST_DEBUG_OBJECT (camerasrc, "Unlock stop");
+
+ if (pclass->unlock_stop)
+ ret = pclass->unlock_stop (camerasrc);
+
+ return ret;
+}
+
+/**
+ * gst_camerasrc_check_autofocus:
+ * @camerasrc: #GstCameraSrc object.
+ *
+ * Check if autofocus has finished. This will be called with STATE_LOCK held.
+ */
+static void
+gst_camerasrc_check_autofocus (GstCameraSrc *camerasrc)
+{
+ GstCameraSrcClass *bclass;
+ GstFocusStatus status;
+ guint32 focused_windows;
+ guint8 focus_rows;
+ guint8 focus_columns;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ status = bclass->get_focus_status (camerasrc,
+ &focused_windows, &focus_rows, &focus_columns);
+
+ GST_DEBUG_OBJECT (camerasrc, "autofocus status: %d", status);
+
+
+ /* FIXME: autofocusing can be continuous. What to do in that case? */
+ if (status == GST_PHOTOGRAPHY_FOCUS_STATUS_SUCCESS ||
+ status == GST_PHOTOGRAPHY_FOCUS_STATUS_FAIL)
+ {
+ GstStructure *s;
+ GstMessage *msg;
+
+ GST_DEBUG_OBJECT (camerasrc, "autofocusing ended");
+
+ /* Send custom GstMessage "autofocus-done" */
+ s = gst_structure_new (GST_PHOTOGRAPHY_AUTOFOCUS_DONE,
+ "status", G_TYPE_INT, status,
+ NULL);
+
+ /* If autofocus succeeded, send the bitmask that defines focused
+ * windows too */
+ if (status == GST_PHOTOGRAPHY_FOCUS_STATUS_SUCCESS) {
+ gst_structure_set (s,
+ "focus_window_mask", G_TYPE_INT, focused_windows,
+ "focus_window_rows", G_TYPE_INT, focus_rows,
+ "focus_window_columns", G_TYPE_INT, focus_columns,
+ NULL);
+
+ GST_DEBUG_OBJECT (camerasrc, "focus rows: %d", focus_rows);
+ GST_DEBUG_OBJECT (camerasrc, "focus columns: %d", focus_columns);
+ GST_DEBUG_OBJECT (camerasrc, "focus mask: %d", focused_windows);
+ }
+
+ msg = gst_message_new_element (GST_OBJECT (camerasrc), s);
+
+ if (gst_element_post_message (GST_ELEMENT (camerasrc), msg) == FALSE) {
+ GST_WARNING ("This element has no bus, therefore no message sent!");
+ }
+
+ /* In still capture mode we don't turn off AF algorithm yet, since it */
+ /* would enable CAF. Instead, it is turned off when application */
+ /* explicitly calls set_autofocus (FALSE), which in turn raises */
+ /* af_requested = OFF flag and AF is finally stopped. */
+
+ /* In video capture mode AF will be stopped immediately to enable AE */
+ if (camerasrc->viewfinder_mode == GST_CAMERA_SRC_VIEWFINDER_MODE_VIDEO) {
+ bclass->set_autofocus (camerasrc, FALSE);
+ }
+
+ /* We don't turn on autoexposure here either. This way AE stays */
+ /* "locked" until application explicitly calls set_autofocus (FALSE). */
+
+ /* state_lock is held, this is safe */
+ camerasrc->photo_capture_phase = GST_CAMERA_AUTOFOCUS_DONE;
+ }
+}
+
+
+/*
+ * gst_camerasrc_send_image_tags:
+ * @camerasrc: #GstCameraSrc object.
+ *
+ */
+static gboolean
+gst_camerasrc_send_image_tags (GstCameraSrc *camerasrc)
+{
+ GstCameraSrcClass *bclass;
+ guint zoom, iso, wbalance;
+ GstEvent *tagevent;
+ GstTagList *tlist;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ tlist = gst_tag_list_new ();
+ zoom = camerasrc->photoconf.zoom;
+ iso = camerasrc->photoconf.iso_speed;
+ wbalance =
+ (camerasrc->photoconf.wb_mode == GST_PHOTOGRAPHY_WB_MODE_AUTO) ? 0 : 1;
+
+ /* Add all possible tags here */
+ gst_tag_list_add (tlist, GST_TAG_MERGE_REPLACE,
+ /* "capture-custom-rendered", 0, G_TYPE_UINT: 0 = normal */
+ GST_TAG_CAPTURING_DIGITAL_ZOOM_RATIO, zoom / 100.0, /* G_TYPE_DOUBLE */
+ GST_TAG_CAPTURING_ISO_SPEED, iso, /* G_TYPE_INT */
+ GST_TAG_CAPTURING_WHITE_BALANCE, wbalance == 0 ? "auto" : "manual", /* G_TYPE_STRING */
+ GST_TAG_CAPTURING_EXPOSURE_PROGRAM, "undefined", /* G_TYPE_STRING */
+ /* "capture-color-space", 1, G_TYPE_UINT: 1 = sRGB */
+ /* "image-xresolution", 300, 1, GST_TYPE_FRACTION */
+ /* "image-yresolution", 300, 1, GST_TYPE_FRACTION */
+ NULL);
+
+ if (bclass->fill_image_tags)
+ bclass->fill_image_tags (camerasrc, tlist);
+
+ tagevent = gst_event_new_tag (gst_tag_list_copy (tlist));
+ gst_pad_push_event (GST_BASE_SRC_PAD (camerasrc), tagevent);
+ GST_DEBUG_OBJECT (camerasrc, "image tags sent: %" GST_PTR_FORMAT, tlist);
+ gst_tag_list_free (tlist);
+
+ return TRUE;
+}
+
+
+/**
+ * gst_camerasrc_send_preview:
+ * @camsrc: #GstCameraSrc object
+ *
+ * Sends HQ image preview image (snapshot) as a GstMessage.
+ *
+ * Returns: TRUE on success.
+ */
+static gboolean
+gst_camerasrc_send_preview (GstCameraSrc *camsrc)
+{
+ GstCameraSrcClass *bclass;
+ GstBuffer *buf = NULL;
+ GstStructure *msg_s = NULL;
+ GstCaps *prvcaps = NULL;
+ GstMessage *msg = NULL;
+ gboolean ret = FALSE;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camsrc);
+
+ if (bclass->get_preview_image) {
+ ret = bclass->get_preview_image (camsrc, &buf);
+ }
+
+ if (ret) {
+ GST_DEBUG_OBJECT (camsrc, "Sending preview image");
+ prvcaps = gst_caps_new_simple ("video/x-raw-yuv",
+ "format", GST_TYPE_FOURCC, camsrc->preview_fourcc,
+ "width", G_TYPE_INT, camsrc->preview_w,
+ "height", G_TYPE_INT, camsrc->preview_h,
+ "framerate", GST_TYPE_FRACTION, 1, 1,
+ NULL);
+
+ gst_buffer_set_caps (buf, prvcaps);
+
+ /* Send custom preview image GstMessage */
+ msg_s = gst_structure_new (GST_CAMERA_SRC_PREVIEW_IMAGE, "buffer",
+ GST_TYPE_BUFFER, buf, NULL);
+
+ msg = gst_message_new_element (GST_OBJECT (camsrc), msg_s);
+
+ if (gst_element_post_message (GST_ELEMENT (camsrc), msg) == FALSE) {
+ GST_WARNING ("This element has no bus, therefore no message sent!");
+ }
+
+ gst_caps_unref (prvcaps);
+ }
+ else {
+ GST_DEBUG_OBJECT (camsrc, "Retrieving preview image failed");
+ }
+
+ /* if we still have valid settings for preview, reserve a new buffer */
+ if (camsrc->preview_resolution_set) {
+ GST_DEBUG_OBJECT (camsrc, "Reserving a new preview buffer");
+ bclass->set_capture (camsrc, GST_PHOTOGRAPHY_OPERATION_MODE_PREVIEW, FALSE,
+ &camsrc->preview_fourcc, &camsrc->preview_w, &camsrc->preview_h,
+ NULL, NULL);
+ }
+
+ if (buf) {
+ gst_buffer_unref (buf);
+ }
+
+ return ret;
+}
+
+
+/**
+ * gst_camerasrc_set_capture_caps:
+ * @camerasrc: #GstCameraSrc object.
+ *
+ * Set the capture caps on element's src pad.
+ *
+ * Returns: TRUE on success.
+ */
+static gboolean
+gst_camerasrc_set_capture_caps (GstCameraSrc *camerasrc)
+{
+ GstCameraSrcClass *bclass;
+ GstCaps *newcaps = NULL;
+ gboolean ret = TRUE;
+ guint32 fourcc;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ fourcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
+
+ GST_DEBUG_OBJECT (camerasrc, "Calling set_capture()");
+
+ /* Try what resolution the subclass can capture */
+ ret = bclass->set_capture (camerasrc,
+ GST_PHOTOGRAPHY_OPERATION_MODE_IMAGE_CAPTURE, TRUE, &fourcc,
+ &camerasrc->capture_w, &camerasrc->capture_h,
+ &camerasrc->capture_fps_n, &camerasrc->capture_fps_d);
+
+ if (!ret) {
+ goto done;
+ }
+
+ /* FIXME: FPS definition should be removed from capture caps */
+ newcaps = gst_camerasrc_get_caps_from_info (camerasrc, fourcc,
+ camerasrc->capture_w, camerasrc->capture_h,
+ camerasrc->capture_fps_n, camerasrc->capture_fps_d);
+
+ GST_DEBUG_OBJECT (camerasrc, "Set capture caps: %" GST_PTR_FORMAT, newcaps);
+
+ /* Notify application that we are ready now. This must be called before */
+ /* the set_caps() call below, since application needs to know the new caps */
+ /* so that it can adjust the caps filter to accept new format before */
+ /* srcpad caps are actually changed */
+ gst_camerasrc_photo_ready_for_capture (camerasrc, newcaps);
+
+ camerasrc->vf_caps =
+ gst_pad_get_negotiated_caps (GST_BASE_SRC_PAD (camerasrc));
+
+ /* This causes caps nego and switches resolution to hi-res mode */
+ /* FIXME: Do we even need to set this? Application has already set the
+ * capsfilter */
+ if (!gst_caps_is_equal (camerasrc->vf_caps, newcaps)) {
+ GST_DEBUG_OBJECT (camerasrc, "Setting image capture caps");
+ ret = gst_pad_set_caps (GST_BASE_SRC_PAD (camerasrc), newcaps);
+ GST_DEBUG_OBJECT (camerasrc, "Setting image capture caps FINISHED");
+ }
+ else {
+ GST_DEBUG_OBJECT (camerasrc, "Forcing the re-initialization");
+ ret = gst_camerasrc_configure_device (camerasrc, &camerasrc->current_w,
+ &camerasrc->current_h, &camerasrc->current_fourcc, &camerasrc->fps_n,
+ &camerasrc->fps_d, newcaps);
+ gst_caps_unref (camerasrc->vf_caps);
+ camerasrc->vf_caps = NULL;
+ }
+
+ gst_caps_unref (newcaps);
+
+done:
+
+ return ret;
+}
+
+
+/*
+ */
+static GstFlowReturn
+gst_camerasrc_create (GstPushSrc * src, GstBuffer ** buf)
+{
+ GstCameraSrcClass *bclass;
+ GstCameraSrc *camerasrc;
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstBuffer *temp;
+
+ camerasrc = GST_CAMERA_SRC_CAST (src);
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+start_over:
+
+ g_mutex_lock (camerasrc->state_lock);
+
+ if (camerasrc->photo_capture_phase == GST_CAMERA_CAPTURE_START) {
+ /* Tell subclass to stop flushing buffers */
+ if (bclass->unlock_stop) {
+ GST_DEBUG_OBJECT (camerasrc, "Stop flushing, capture is starting");
+ bclass->unlock_stop (camerasrc);
+ }
+
+ camerasrc->photo_capture_phase = GST_CAMERA_CAPTURE;
+
+ GST_DEBUG_OBJECT (camerasrc, "Flushing old buffers before starting HQ capture");
+ gst_pad_push_event (GST_BASE_SRC_PAD (camerasrc), gst_event_new_flush_start ());
+ gst_pad_push_event (GST_BASE_SRC_PAD (camerasrc), gst_event_new_flush_stop ());
+
+ if (!gst_camerasrc_set_capture_caps (camerasrc)) {
+ goto hq_capture_failed;
+ }
+ }
+
+ else if (camerasrc->photo_capture_phase == GST_CAMERA_CAPTURE_DONE) {
+
+ gboolean ret;
+
+ camerasrc->photo_capture_phase = GST_CAMERA_VIEWFINDER;
+ camerasrc->requested_af_mode = AF_OFF_REQUESTED;
+
+ GST_DEBUG_OBJECT (camerasrc, "capture done. switching to viewfinder");
+
+ /* Set the normal viewfinder resolution back */
+ if (camerasrc->vf_caps) {
+ GST_DEBUG_OBJECT (camerasrc, "set VF caps");
+ ret = gst_pad_set_caps (GST_BASE_SRC_PAD (camerasrc), camerasrc->vf_caps);
+ gst_caps_unref (camerasrc->vf_caps);
+ camerasrc->vf_caps = NULL;
+ }
+ else {
+ GstCaps *tmp;
+
+ tmp = gst_pad_get_negotiated_caps (GST_BASE_SRC_PAD (camerasrc));
+
+ /* Reconfigure the device to run viewfinder again */
+ ret = gst_camerasrc_configure_device (camerasrc, &camerasrc->current_w,
+ &camerasrc->current_h, &camerasrc->current_fourcc, &camerasrc->fps_n,
+ &camerasrc->fps_d, tmp);
+
+ gst_caps_unref (tmp);
+ }
+
+ if (!ret) {
+ GST_WARNING_OBJECT (camerasrc, "Reinitializing viewfinder failed");
+ g_mutex_unlock (camerasrc->state_lock);
+ return GST_FLOW_ERROR;
+ }
+
+ GST_DEBUG_OBJECT (camerasrc, "viewfinder running");
+ }
+
+ g_mutex_lock (camerasrc->af_lock);
+
+ /* Handle AF requests only in VIEWFINDER and AUTOFOCUS states */
+ if ((camerasrc->photo_capture_phase == GST_CAMERA_VIEWFINDER ||
+ camerasrc->photo_capture_phase == GST_CAMERA_AUTOFOCUS ||
+ camerasrc->photo_capture_phase == GST_CAMERA_AUTOFOCUS_DONE) &&
+ camerasrc->requested_af_mode != AF_NONE_REQUESTED)
+ {
+ if (camerasrc->requested_af_mode == AF_ON_REQUESTED) {
+ gboolean ret;
+
+ /* In still capture mode AE will be locked during AF operation */
+ if (camerasrc->viewfinder_mode == GST_CAMERA_SRC_VIEWFINDER_MODE_STILL) {
+ bclass->set_autoexposure (camerasrc, FALSE);
+ }
+ ret = bclass->set_autofocus (camerasrc, TRUE);
+
+ if (ret) {
+ camerasrc->photo_capture_phase = GST_CAMERA_AUTOFOCUS;
+ } else {
+ /* Starting AF failed, so start AE again */
+ bclass->set_autoexposure (camerasrc, TRUE);
+ }
+ }
+ else {
+ bclass->set_autofocus (camerasrc, FALSE);
+ bclass->set_autoexposure (camerasrc, TRUE);
+ camerasrc->photo_capture_phase = GST_CAMERA_VIEWFINDER;
+ }
+
+ camerasrc->requested_af_mode = AF_NONE_REQUESTED;
+ }
+
+ g_mutex_unlock (camerasrc->af_lock);
+ g_mutex_unlock (camerasrc->state_lock);
+
+ ret = bclass->grab_frame (camerasrc, &temp, camerasrc->photo_capture_phase);
+
+ g_mutex_lock (camerasrc->state_lock);
+
+ if (ret != GST_FLOW_OK) {
+ /* _prepare_for_capture() may have interrupted frame grabbing. */
+ if (ret == GST_FLOW_WRONG_STATE &&
+ camerasrc->photo_capture_phase == GST_CAMERA_CAPTURE_START)
+ {
+ g_mutex_unlock (camerasrc->state_lock);
+ ret = GST_FLOW_OK;
+ goto start_over;
+ } else {
+ g_mutex_unlock (camerasrc->state_lock);
+ goto leave;
+ }
+ }
+
+ *buf = temp;
+
+ /* Post-capture phase */
+
+ if (camerasrc->photo_capture_phase == GST_CAMERA_CAPTURE) {
+ GstCaps *src_caps;
+
+ src_caps = gst_pad_get_negotiated_caps (GST_BASE_SRC_PAD (camerasrc));
+ gst_buffer_set_caps (*buf, src_caps);
+ gst_caps_unref (src_caps);
+
+ /* Restore the original number of buffers after capture is done */
+ /* FIXME: Commented out */
+// camerasrc->num_buffers = tmp_num_buffers;
+
+ gst_camerasrc_send_image_tags (camerasrc);
+
+ gst_camerasrc_send_preview (camerasrc);
+
+ camerasrc->photo_capture_phase = GST_CAMERA_CAPTURE_DONE;
+ }
+
+ else if (camerasrc->photo_capture_phase == GST_CAMERA_AUTOFOCUS) {
+ /* this function sets the capture phase to "VIEWFINDER" when
+ autofocus is done / fails */
+ g_mutex_lock (camerasrc->af_lock);
+ gst_camerasrc_check_autofocus (camerasrc);
+ g_mutex_unlock (camerasrc->af_lock);
+ }
+
+done:
+
+ g_mutex_unlock (camerasrc->state_lock);
+
+leave:
+ return ret;
+
+ /* ERRORS */
+hq_capture_failed:
+ GST_ELEMENT_ERROR (camerasrc, RESOURCE, READ,
+ ("Error during HQ capture"), (NULL));
+ ret = GST_FLOW_ERROR;
+ goto done;
+}
+
+
+static GstStateChangeReturn
+gst_camerasrc_change_state (GstElement * element, GstStateChange transition)
+{
+ GstCameraSrcClass *bclass;
+ GstCameraSrc *camerasrc;
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+ camerasrc = GST_CAMERA_SRC_CAST (element);
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+
+ GST_LOG_OBJECT (camerasrc, "State change: %s -> %s",
+ gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
+ gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ /* Open the device */
+ if (!bclass->open (camerasrc))
+ return GST_STATE_CHANGE_FAILURE;
+ break;
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ if (bclass->is_open (camerasrc)) {
+ bclass->close (camerasrc);
+ }
+ camerasrc->capture_w = camerasrc->preview_w = camerasrc->current_w = 0;
+ camerasrc->capture_h = camerasrc->preview_h = camerasrc->current_h = 0;
+ camerasrc->capture_fourcc = camerasrc->preview_fourcc = 0;
+ camerasrc->current_fourcc = 0;
+ camerasrc->fps_d = camerasrc->fps_n = 0;
+ camerasrc->capture_resolution_set = FALSE;
+ camerasrc->preview_resolution_set = FALSE;
+
+ /* Notify that preview caps have changed (to NULL) */
+ g_object_notify (G_OBJECT (camerasrc),
+ GST_PHOTOGRAPHY_PROP_IMAGE_PREVIEW_SUPPORTED_CAPS);
+
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+
+/**
+ * gst_camerasrc_add_color_channel:
+ * @camsrc: #GstCameraSrc object.
+ * @channel: #GstColorBalanceChannel object.
+ *
+ * Add a new color channel to list.
+ */
+void
+gst_camerasrc_add_color_channel (GstCameraSrc *camsrc,
+ GstColorBalanceChannel *channel)
+{
+ camsrc->colors = g_list_append (camsrc->colors, (gpointer) channel);
+}
+
+
+/**
+ * gst_camerasrc_clear_color_channels:
+ * @camsrc: #GstCameraSrc object.
+ *
+ * Delete all color channels.
+ */
+void gst_camerasrc_clear_color_channels (GstCameraSrc *camsrc)
+{
+ g_list_foreach (camsrc->colors, (GFunc) g_object_unref, NULL);
+ g_list_free (camsrc->colors);
+ camsrc->colors = NULL;
+}
+
+
+/**
+ * gst_camerasrc_send_capture_start_message:
+ * @camsrc: GstCameraSrc object
+ *
+ * Sends a GstMessage notification to GstBus that capture operation is
+ * about to start.
+ */
+void
+gst_camerasrc_send_capture_start_message (GstCameraSrc *camsrc)
+{
+ GstStructure *s;
+ GstMessage *msg;
+
+ GST_DEBUG_OBJECT (camsrc, "Sending capture-start message");
+
+ /* Send custom GstMessage "photo-capture-start" */
+ s = gst_structure_new (GST_CAMERA_SRC_CAPTURE_START, NULL);
+ msg = gst_message_new_element (GST_OBJECT (camsrc), s);
+
+ if (gst_element_post_message (GST_ELEMENT (camsrc), msg) == FALSE) {
+ GST_WARNING ("This element has no bus, therefore no message sent!");
+ }
+
+ GST_LOG_OBJECT (camsrc, "Capture-start message sent");
+}
+
+
+/**
+ * gst_camerasrc_send_capture_stop_message:
+ * @camsrc: GstCameraSrc object
+ *
+ * Sends a GstMessage notification to GstBus that capture operation has
+ * just finished.
+ */
+void
+gst_camerasrc_send_capture_stop_message (GstCameraSrc *camsrc)
+{
+ GstStructure *s;
+ GstMessage *msg;
+
+ GST_DEBUG_OBJECT (camsrc, "Sending capture-stop message");
+
+ /* Send custom GstMessage "photo-capture-end" */
+ s = gst_structure_new (GST_CAMERA_SRC_CAPTURE_END, NULL);
+ msg = gst_message_new_element (GST_OBJECT (camsrc), s);
+
+ if (gst_element_post_message (GST_ELEMENT (camsrc), msg) == FALSE) {
+ GST_WARNING ("This element has no bus, therefore no message sent!");
+ }
+
+ GST_LOG_OBJECT (camsrc, "Capture-stop message sent");
+}
+
+
+/**
+ * gst_camerasrc_send_caf_update_message:
+ * @camsrc: GstCameraSrc object.
+ * @status: new continuous autofocus status.
+ *
+ * Sends a GstMessage notification to GstBus indicating a change in
+ * continuous autofocus status.
+ */
+void gst_camerasrc_send_caf_update_message (GstCameraSrc *camsrc,
+ GstCameraCAFStatus status)
+{
+ GstStructure *s;
+ GstMessage *msg;
+
+ GST_DEBUG_OBJECT (camsrc, "Sending CAF status: %d", status);
+
+ /* Send custom GstMessage "caf-update" */
+ s = gst_structure_new (GST_CAMERA_SRC_CAF_STATUS, NULL);
+ gst_structure_set (s, "status", G_TYPE_INT, status, NULL);
+ msg = gst_message_new_element (GST_OBJECT (camsrc), s);
+
+ if (gst_element_post_message (GST_ELEMENT (camsrc), msg) == FALSE) {
+ GST_WARNING ("This element has no bus, therefore no message sent!");
+ }
+
+ GST_LOG_OBJECT (camsrc, "CAF update message sent");
+}
+
+/* Default implementations for vmethods */
+
+static GstPhotoCaps
+gst_camerasrc_default_capabilities (GstCameraSrc *camsrc)
+{
+ return GST_PHOTOGRAPHY_CAPS_NONE;
+}
+
+static gboolean
+gst_camerasrc_default_ret_true_with_settings (GstCameraSrc *camsrc,
+ GstPhotoSettings *photoconf)
+{
+ return TRUE;
+}
+
+static gboolean
+gst_camerasrc_default_write_settings (GstCameraSrc *camsrc,
+ GstPhotoSettings *photoconf,
+ gboolean scene_mode_override)
+{
+ return TRUE;
+}
+
+static gboolean
+gst_camerasrc_default_set_onoff (GstCameraSrc *camsrc, gboolean on_off)
+{
+ return TRUE;
+}
+
+static GstFocusStatus
+gst_camerasrc_default_get_focus_status (GstCameraSrc *camsrc,
+ guint32 *focused_windows_bitmask,
+ guint8 *focus_rows,
+ guint8 *focus_columns)
+{
+ *focused_windows_bitmask = *focus_rows = *focus_columns = 0;
+ return GST_PHOTOGRAPHY_FOCUS_STATUS_NONE;
+}
+
+static GstCaps *
+gst_camerasrc_default_get_caps (GstCameraSrc *camsrc, GstOperationMode mode)
+{
+ GST_DEBUG_OBJECT (camsrc, "Returning NULL caps for mode %d", mode);
+
+ return NULL;
+}
+
+static void
+gst_camerasrc_default_functions_init (GstCameraSrcClass *camera_class)
+{
+ camera_class->get_capabilities = gst_camerasrc_default_capabilities;
+ camera_class->set_autofocus = gst_camerasrc_default_set_onoff;
+ camera_class->set_autoexposure = gst_camerasrc_default_set_onoff;
+ camera_class->get_focus_status = gst_camerasrc_default_get_focus_status;
+ camera_class->read_settings = gst_camerasrc_default_ret_true_with_settings;
+ camera_class->write_settings = gst_camerasrc_default_write_settings;
+ camera_class->get_supported_caps = gst_camerasrc_default_get_caps;
+
+ GST_DEBUG ("Default functions set");
+}
+
+
+static gboolean
+gst_camerasrc_handle_event (GstCameraSrc *camerasrc, GstEvent *event)
+{
+ GstCameraSrcClass *bclass;
+ gboolean ret = FALSE;
+
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+ GST_LOG_OBJECT (camerasrc, "handling %s event", GST_EVENT_TYPE_NAME (event));
+
+ if (bclass->event) {
+ ret = bclass->event (camerasrc, event);
+ }
+
+ return ret;
+}
+
+
+/*
+ * gst_camerasrc_send_event:
+ * @element: GstElement object.
+ * @event: GstEvent to be handled.
+ *
+ * Returns: TRUE if the event was handled.
+ */
+static gboolean
+gst_camerasrc_send_event (GstElement * element, GstEvent * event)
+{
+ GstCameraSrc *camerasrc;
+ gboolean ret = FALSE;
+
+ camerasrc = GST_CAMERA_SRC_CAST (element);
+
+ GST_LOG_OBJECT (camerasrc, "got %s event", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_CUSTOM_UPSTREAM:
+ ret = gst_camerasrc_handle_event (camerasrc, event);
+ break;
+ default:
+ break;
+ }
+
+ if (!ret) {
+ ret = GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
+ }
+
+ return ret;
+}
+
+
+/*
+ * gst_camerasrc_event:
+ * @src: #GstBaseSrc object.
+ * @event: #GetEvent object.
+ *
+ * Returns: TRUE of the event was handled.
+ */
+static gboolean
+gst_camerasrc_event (GstBaseSrc * src, GstEvent * event)
+{
+ GstCameraSrc *camerasrc;
+ gboolean ret;
+
+ camerasrc = GST_CAMERA_SRC_CAST (src);
+ ret = gst_camerasrc_handle_event (camerasrc, event);
+
+ if (!ret) {
+ ret = GST_BASE_SRC_CLASS (parent_class)->event (src, event);
+ }
+
+ return ret;
+}
+
+
+/**
+ * gst_camerasrc_update_max_zoom:
+ * @camerasrc: #GstCameraSrc object.
+ *
+ * Check and update zoom property maximum value.
+ */
+static void
+gst_camerasrc_update_max_zoom (GstCameraSrc *camerasrc)
+{
+ GstCameraSrcClass *bclass;
+ GObjectClass *oclass;
+ GParamSpec *pspec;
+ GParamSpecInt *pspec_i;
+ gfloat maxzoom = 4.0;
+
+ oclass = G_OBJECT_GET_CLASS (camerasrc);
+ bclass = GST_CAMERA_SRC_GET_CLASS (camerasrc);
+ pspec = g_object_class_find_property (oclass, "zoom");
+
+ if (bclass->get_max_zoom) {
+ if (!bclass->get_max_zoom (camerasrc, &maxzoom)) {
+ maxzoom = 4.0;
+ }
+ }
+
+ /* Update gobject property */
+ if (pspec && (G_PARAM_SPEC_VALUE_TYPE (pspec) == G_TYPE_INT)) {
+ pspec_i = G_PARAM_SPEC_INT (pspec);
+ pspec_i->maximum = (gint) (maxzoom * 100.0);
+ GST_DEBUG_OBJECT (camerasrc, "set maximum zoom as %d", pspec_i->maximum);
+ /* Check if new maximum zoom is lower than current zoom level */
+ if (pspec_i->maximum < camerasrc->photoconf.zoom) {
+ GST_DEBUG_OBJECT (camerasrc, "current zoom level too high: %d",
+ camerasrc->photoconf.zoom);
+ g_object_set (G_OBJECT (camerasrc), "zoom", pspec_i->maximum, NULL);
+ }
+ } else {
+ GST_WARNING_OBJECT (camerasrc, "updating maximum zoom failed");
+ }
+}
--- /dev/null
+/* GStreamer
+ *
+ * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * 2006 Edgard Lima <edgard.lima@indt.org.br>
+ * 2008-2010 Nokia Corporation <multimedia@maemo.org>
+ *
+ * gstcamerasrc.h: Abstract camera source base class
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_CAMSRC_H__
+#define __GST_CAMSRC_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstpushsrc.h>
+#include <gst/interfaces/photography.h>
+#include <gst/interfaces/colorbalance.h>
+
+#define GST_CAMERA_SRC_MAX_SIZE (1<<15) /* 2^15 == 32768 */
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_CAMERA_SRC (gst_camerasrc_get_type())
+#define GST_CAMERA_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CAMERA_SRC,GstCameraSrc))
+#define GST_CAMERA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CAMERA_SRC,GstCameraSrcClass))
+#define GST_CAMERA_SRC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_CAMERA_SRC,GstCameraSrcClass))
+#define GST_IS_CAMERA_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CAMERA_SRC))
+#define GST_IS_CAMERA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CAMERA_SRC))
+
+#define GST_CAMERA_SRC_CAST(obj) ((GstCameraSrc *)(obj))
+#define GST_CAMERA_SRC_CLASS_CAST(klass) ((GstCameraSrcClass *)(klass))
+
+#define GST_TYPE_CAMERA_SRC_CAPTURE_MODE (gst_camerasrc_capture_mode_get_type())
+#define GST_TYPE_CAMERA_SRC_VIEWFINDER_MODE (gst_camerasrc_viewfinder_mode_get_type())
+
+/**
+ * GST_CAMERA_SRC_CAPTURE_START:
+ *
+ * Message that is sent when capturing process is about to start.
+ */
+#define GST_CAMERA_SRC_CAPTURE_START "photo-capture-start"
+
+/**
+ * GST_CAMERA_SRC_CAPTURE_END:
+ *
+ * Message that is sent when capturing process has finished.
+ */
+#define GST_CAMERA_SRC_CAPTURE_END "photo-capture-end"
+
+/**
+ * GST_CAMERA_SRC_PREVIEW_IMAGE:
+ *
+ * This message is used to send the preview image to application. Message will
+ * contain one field called "buffer" which will hold a GstBuffer containing
+ * the preview image data.
+ */
+#define GST_CAMERA_SRC_PREVIEW_IMAGE "photo-capture-preview"
+
+/**
+* GST_CAMERA_SRC_CAF_STATUS:
+*
+* Continuous autofocus algorithm status update message.
+*/
+#define GST_CAMERA_SRC_CAF_STATUS "caf-update"
+
+/**
+ * GstCameraSrcCaptureMode:
+ * @GST_CAMERA_SRC_CAPTURE_MODE_VIEWFINDER: Viewfinder is running.
+ * @GST_CAMERA_SRC_CAPTURE_MODE_STILL: Still image capture mode.
+ * @GST_CAMERA_SRC_CAPTURE_MODE_VIDEO: Video capture mode.
+ *
+ * Camera element capturing modes.
+ */
+typedef enum {
+ GST_CAMERA_SRC_CAPTURE_MODE_VIEWFINDER,
+ GST_CAMERA_SRC_CAPTURE_MODE_STILL,
+ GST_CAMERA_SRC_CAPTURE_MODE_VIDEO
+} GstCameraSrcCaptureMode;
+
+
+/**
+ * GstCameraSrcViewfinderMode:
+ * @GST_CAMERA_SRC_VIEWFINDER_MODE_STILL: Still image capture VF mode.
+ * @GST_CAMERA_SRC_VIEWFINDER_MODE_VIDEO: Video capture VF mode.
+ *
+ * Defines in which mode viewfinder should be run.
+ */
+typedef enum {
+ GST_CAMERA_SRC_VIEWFINDER_MODE_STILL,
+ GST_CAMERA_SRC_VIEWFINDER_MODE_VIDEO
+} GstCameraSrcViewfinderMode;
+
+
+/**
+ * GstCameraSrcAFReqMode:
+ * @AF_NONE_REQUESTED: No change to AF mode requested.
+ * @AF_OFF_REQUESTED: AF should be turned off.
+ * @AF_ON_REQUESTED: AF should be turned on.
+ *
+ * Requested autofocus status.
+ */
+typedef enum {
+ AF_NONE_REQUESTED = 0,
+ AF_OFF_REQUESTED,
+ AF_ON_REQUESTED
+} GstCameraSrcAFReqMode;
+
+
+/**
+* GstCameraCAFStatus:
+* @CAF_IDLE: CAF is not running.
+* @CAF_RUNNING: CAF algorithm is running.
+* @CAF_SUCCESS: CAF got a focus.
+* @CAF_FAILED: CAF failed to got a focus.
+*
+* Send continuous autofocus status update.
+*/
+typedef enum {
+ CAF_IDLE = 0,
+ CAF_RUNNING,
+ CAF_SUCCESS,
+ CAF_FAILED
+} GstCameraCAFStatus;
+
+
+/**
+ * GstCameraCapturePhase:
+ * @GST_CAMERA_OFF: photo capturing functionality disabled.
+ * @GST_CAMERA_VIEWFINDER: element is running in viewfinder mode.
+ * @GST_CAMERA_AUTOFOCUS: element is running autofocus phase.
+ * @GST_CAMERA_AUTOFOCUS_DONE: autofocus phase has ended.
+ * @GST_CAMERA_CAPTURE_START: element is preparing to capture HQ image.
+ * @GST_CAMERA_CAPTURE: element is capturing HQ image.
+ * @GST_CAMERA_CAPTURE_DONE: finishing HQ capture operation.
+ *
+ * Photo capturing phases.
+ */
+typedef enum {
+ GST_CAMERA_OFF = 0,
+ GST_CAMERA_VIEWFINDER,
+ GST_CAMERA_AUTOFOCUS,
+ GST_CAMERA_AUTOFOCUS_DONE,
+ GST_CAMERA_CAPTURE_START,
+ GST_CAMERA_CAPTURE,
+ GST_CAMERA_CAPTURE_DONE
+} GstCameraCapturePhase;
+
+
+typedef struct _GstCameraSrc GstCameraSrc;
+typedef struct _GstCameraSrcClass GstCameraSrcClass;
+
+
+/**
+ * GstCameraSrc:
+ * @element: the parent element.
+ *
+ * Opaque #GstCameraSrc object.
+ */
+struct _GstCameraSrc {
+ GstPushSrc element;
+
+ /*< private >*/
+ GstCaps *vf_caps;
+ GList *colors;
+
+ /* TRUE if outgoing buffer should be always duplicated */
+ gboolean always_copy;
+
+ /* Current video device format */
+ guint current_w, current_h; /* current capture frame size */
+ guint fps_d, fps_n; /* framerate if device is open */
+ guint32 current_fourcc; /* current color format */
+
+ /* Photo interface -related */
+ GstPhotoSettings photoconf; /* Caches the settings */
+ GMutex *state_lock;
+ GMutex *af_lock;
+ GstPhotoCapturePrepared prep_func;
+ gpointer prep_udata;
+
+ /* Image capture format */
+ guint capture_w, capture_h;
+ guint capture_fps_n, capture_fps_d;
+ guint32 capture_fourcc;
+ gboolean capture_resolution_set; /* Is capture resolution set already? */
+
+ /* Preview image format */
+ guint preview_w, preview_h;
+ guint32 preview_fourcc;
+ gboolean preview_resolution_set; /* Is preview resolution set already? */
+
+ GstCameraSrcCaptureMode capture_mode;
+ GstCameraSrcViewfinderMode viewfinder_mode;
+
+ /* Protected with state_lock */
+ GstCameraCapturePhase photo_capture_phase;
+
+ guint8 requested_af_mode;
+};
+
+
+/**
+ * GstCameraSrcClass:
+ * @parent_class: the parent class structure.
+ * @open: Called when subclass should open the video device.
+ * @is_open: Called to get information if video device is currently open.
+ * @close: Called when subclass should close video device and free resources.
+ * @get_attribute: Called to get V4L2 attribute from device.
+ * @set_attribute: Called to set V4L2 attribute to device.
+ * @set_capture: Called to set VF/capture/preview resolution & format.
+ * @start: Capturing should start.
+ * @is_active: Ask subclass whether capturing is ongoing.
+ * @grab_frame: Ask the subclass to capture a frame.
+ * @stop: Subclass should stop capturing frames from device.
+ * @get_caps: Ask the subclass for supported output (viewfinder) caps.
+ * @get_num_buffers: Ask the subclass how many video buffers it is using.
+ * @unlock: Tell the subclass to stop any pending operation to video device.
+ * @unlock_stop: Clear previous unlock request.
+ * @fill_image_tags: Called after image capturing to retrieve image metadata.
+ * @get_preview_image: Called after image capture to retrieve preview image.
+ * @event: Used for passing custom events to subclass.
+ * @get_capabilities: Ask what capabilities subclass has.
+ * @set_vfinder_mode: Set viewfinder mode.
+ * @set_capture_mode: Set capturing mode.
+ * @set_autofocus: Turn on / off autofocus algorithm.
+ * @set_autoexposure: Turn on / off auto exposure algorithm.
+ * @get_focus_status: Used for querying the AF status during focus operation.
+ * @write_settings: Write all GstPhotoSettings to subclass at once.
+ * @read_settings: Read all device settings to given GstPhotoSettings structure.
+ * @set_zoom: Set the zoom factor.
+ * @get_max_zoom: Ask for maximum zoom factor that can be used.
+ * @get_supported_caps: Ask subclass about supported caps for given mode.
+ *
+ * #GstCameraSrc class object.
+ */
+struct _GstCameraSrcClass
+{
+ GstPushSrcClass parent_class;
+
+ /*< public >*/
+ /* virtual methods for subclasses */
+ gboolean (*open) (GstCameraSrc *camsrc);
+
+ gboolean (*is_open) (GstCameraSrc *camsrc);
+
+ gboolean (*close) (GstCameraSrc *camsrc);
+
+ /* attribute control */
+ gboolean (*get_attribute) (GstCameraSrc *camsrc, int attribute,
+ int *value);
+
+ gboolean (*set_attribute) (GstCameraSrc *camsrc, int attribute,
+ const int value);
+
+ gboolean (*set_capture) (GstCameraSrc *camsrc,
+ GstOperationMode mode,
+ gboolean try_only,
+ guint32 *pixelformat,
+ guint *width, guint32 *height,
+ guint *fps_n, guint *fps_d);
+
+ gboolean (*start) (GstCameraSrc *camsrc, GstCaps *caps);
+
+ gboolean (*is_active) (GstCameraSrc *camsrc);
+
+ GstFlowReturn (*grab_frame) (GstCameraSrc *camsrc, GstBuffer **buf,
+ GstCameraCapturePhase phase);
+
+ gboolean (*stop) (GstCameraSrc *camsrc);
+
+ GstCaps* (*get_caps) (GstCameraSrc *camsrc);
+
+ guint (*get_num_buffers) (GstCameraSrc *camsrc);
+
+ gboolean (*unlock) (GstCameraSrc *camsrc);
+
+ gboolean (*unlock_stop) (GstCameraSrc *camsrc);
+
+ gboolean (*fill_image_tags) (GstCameraSrc *camsrc, GstTagList *tlist);
+
+ gboolean (*get_preview_image) (GstCameraSrc *camsrc, GstBuffer **buf);
+
+ gboolean (*event) (GstCameraSrc *camsrc, GstEvent *event);
+
+ /* FORMER DRIVER-API */
+
+ GstPhotoCaps
+ (*get_capabilities) (GstCameraSrc *camsrc);
+
+ gboolean
+ (*set_vfinder_mode) (GstCameraSrc *camsrc,
+ GstCameraSrcViewfinderMode mode);
+
+ gboolean
+ (*set_capture_mode) (GstCameraSrc *camsrc,
+ GstCameraSrcCaptureMode mode);
+
+ gboolean
+ (*set_autofocus) (GstCameraSrc *camsrc, gboolean on_off);
+
+ gboolean
+ (*set_autoexposure) (GstCameraSrc *camsrc, gboolean on_off);
+
+ GstFocusStatus
+ (*get_focus_status) (GstCameraSrc *camsrc,
+ guint32 *focused_windows_bitmask,
+ guint8 *focus_rows,
+ guint8 *focus_columns);
+
+ gboolean
+ (*write_settings) (GstCameraSrc *camsrc,
+ GstPhotoSettings *photoconf,
+ gboolean scene_mode_override);
+
+ gboolean
+ (*read_settings) (GstCameraSrc *camsrc, GstPhotoSettings *photoconf);
+
+ gboolean
+ (*set_zoom) (GstCameraSrc *camsrc, gfloat zoomfactor);
+
+ gboolean
+ (*get_max_zoom) (GstCameraSrc *camsrc, gfloat *maxzoom);
+
+ GstCaps *
+ (*get_supported_caps) (GstCameraSrc *camsrc, GstOperationMode mode);
+
+ /*< private >*/
+ gpointer _gst_reserved[GST_PADDING_LARGE];
+};
+
+
+GType gst_camerasrc_get_type (void);
+
+
+void gst_camerasrc_add_color_channel (GstCameraSrc *camsrc,
+ GstColorBalanceChannel *channel);
+
+void gst_camerasrc_clear_color_channels (GstCameraSrc *camsrc);
+
+void gst_camerasrc_send_capture_start_message (GstCameraSrc *camsrc);
+
+void gst_camerasrc_send_capture_stop_message (GstCameraSrc *camsrc);
+
+void gst_camerasrc_send_caf_update_message (GstCameraSrc *camsrc,
+ GstCameraCAFStatus status);
+
+GstCaps *
+gst_camerasrc_get_caps_from_info (GstCameraSrc *camsrc, guint32 fourcc,
+ guint width, guint height, guint fps_n, guint fps_d);
+
+G_END_DECLS
+
+#endif /* __GST_CAMSRC_H__ */
--- /dev/null
+SUBDIRS = v4l2newcam
+DIST_SUBDIRS= v4l2newcam
--- /dev/null
+plugin_LTLIBRARIES = libgstv4l2newcam.la
+
+libgstv4l2newcamincludedir = \
+ $(includedir)/gstreamer-@GST_MAJORMINOR@/gst
+
+libgstv4l2newcam_la_SOURCES = gstv4l2camvidorient.c \
+ gstv4l2camsrc.c \
+ v4l2camsrc_calls.c
+
+libgstv4l2newcam_la_CFLAGS = -I$(top_builddir)/gst-libs \
+ $(GST_CFLAGS) \
+ $(GST_BASE_CFLAGS) \
+ $(GST_BAD_CFLAGS) \
+ -DGST_USE_UNSTABLE_API
+
+libgstv4l2newcam_la_LIBADD = $(top_builddir)/gst-libs/gst/camera/libgstcamera-$(GST_MAJORMINOR).la \
+ $(GST_LIBS) \
+ $(GST_BASE_LIBS) \
+ $(GST_BAD_LIBS) \
+ -lgstinterfaces-$(GST_MAJORMINOR) \
+ -lgstphotography-$(GST_MAJORMINOR)
+
+
+libgstv4l2newcam_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstv4l2newcam_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = v4l2camsrc_calls.h gstv4l2camvidorient.h
--- /dev/null
+/* GStreamer V4L2 camera source
+ * Copyright (C) 2010 Nokia Corporation <multimedia@maemo.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-v4l2newcamsrc
+ * @short_description: V4L2 camera source
+ * @see_also: #GstCameraSrc
+ *
+ * <refsect2>
+ * <para>
+ * Bla bla...
+ * </para>
+ * <para>
+ * Foo bar
+ * </para>
+ * <title>Example launch line</title>
+ * <para>
+ * <programlisting>
+ * gst-launch v4l2camsrc ! xvimagesink
+ * </programlisting>
+ * </para>
+ * </refsect2>
+ */
+
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstv4l2camsrc.h"
+#include "v4l2camsrc_calls.h"
+#include "gstv4l2camvidorient.h"
+
+
+GST_DEBUG_CATEGORY (gst_v4l2camsrc_debug);
+#define GST_CAT_DEFAULT gst_v4l2camsrc_debug
+
+static gboolean gst_v4l2camsrc_is_open (GstCameraSrc *camsrc);
+static void gst_v4l2camsrc_finalize (GObject * object);
+static void gst_v4l2camsrc_dispose (GObject * object);
+static void gst_v4l2camsrc_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_v4l2camsrc_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec);
+static gboolean gst_v4l2camsrc_unlock (GstCameraSrc * src);
+static gboolean gst_v4l2camsrc_unlock_stop (GstCameraSrc * src);
+static gboolean gst_v4l2camsrc_iface_supported (GstImplementsInterface * iface,
+ GType iface_type);
+
+typedef enum {
+ PROP_0,
+ PROP_DEVICE,
+ PROP_DEVICE_FD,
+ PROP_DEVICE_NAME,
+ PROP_QUEUE_SIZE,
+} GstV4L2CamSrcProperties;
+
+
+static GstStaticPadTemplate gst_v4l2camsrc_src_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-raw-yuv, "
+ "format = (fourcc) UYVY, "
+ "framerate = (fraction) [ 0, 200 ], "
+ "width = (int) [ 1, MAX ], "
+ "height = (int) [ 1, MAX ];"
+ "video/x-raw-yuv, "
+ "format = (fourcc) I420, "
+ "framerate = (fraction) [ 0, 200 ], "
+ "width = (int) [ 1, MAX ], "
+ "height = (int) [ 1, MAX ];"
+ "video/x-raw-yuv, "
+ "format = (fourcc) YUY2, "
+ "framerate = (fraction) [ 0, 200 ], "
+ "width = (int) [ 1, MAX ], "
+ "height = (int) [ 1, MAX ];"
+ "video/x-raw-bayer, "
+ "framerate = (fraction) [ 0, 200 ], "
+ "width = (int) [ 1, MAX ], "
+ "height = (int) [ 1, MAX ]"));
+
+
+#define DEFAULT_PROP_DEVICE_NAME NULL
+#define DEFAULT_PROP_DEVICE "/dev/video0"
+#define DEFAULT_PROP_DEVICE_FD -1
+
+GST_IMPLEMENT_V4L2CAMSRC_VIDORIENT_METHODS (GstV4l2NewCamSrc, gst_v4l2camsrc);
+
+
+static void
+gst_v4l2camsrc_interface_init (GstImplementsInterfaceClass * klass)
+{
+ /*
+ * default virtual functions
+ */
+ klass->supported = gst_v4l2camsrc_iface_supported;
+}
+
+void
+gst_v4l2camsrc_init_interfaces (GType type)
+{
+ static const GInterfaceInfo v4l2camsrc_iface_info = {
+ (GInterfaceInitFunc) gst_v4l2camsrc_interface_init,
+ NULL,
+ NULL,
+ };
+ static const GInterfaceInfo v4l2camsrc_videoorientation_info = {
+ (GInterfaceInitFunc) gst_v4l2camsrc_video_orientation_interface_init,
+ NULL,
+ NULL,
+ };
+
+ g_type_add_interface_static (type,
+ GST_TYPE_IMPLEMENTS_INTERFACE, &v4l2camsrc_iface_info);
+ g_type_add_interface_static (type,
+ GST_TYPE_VIDEO_ORIENTATION, &v4l2camsrc_videoorientation_info);
+}
+
+
+GST_BOILERPLATE_FULL (GstV4l2NewCamSrc, gst_v4l2camsrc, GstCameraSrc,
+ GST_TYPE_CAMERA_SRC, gst_v4l2camsrc_init_interfaces);
+
+
+
+static gboolean
+gst_v4l2camsrc_iface_supported (GstImplementsInterface * iface, GType iface_type)
+{
+ GstCameraSrc *camsrc = GST_CAMERA_SRC (iface);
+
+ if (gst_v4l2camsrc_is_open (camsrc) &&
+ iface_type == GST_TYPE_VIDEO_ORIENTATION)
+ {
+ return TRUE;
+ }
+
+ else if (GST_IS_IMPLEMENTS_INTERFACE (camsrc)) {
+ GstImplementsInterfaceClass * parent_klass;
+
+ parent_klass =
+ g_type_interface_peek (parent_class, GST_TYPE_IMPLEMENTS_INTERFACE);
+ return parent_klass->supported (iface, iface_type);
+ }
+
+ return FALSE;
+}
+
+
+/*
+ * gst_v4l2camsrc_is_open:
+ *
+ */
+static gboolean
+gst_v4l2camsrc_is_open (GstCameraSrc *camsrc)
+{
+ GstV4l2NewCamSrc *v4l2camsrc = GST_V4L2CAMSRC (camsrc);
+
+ return GST_V4L2CAMSRC_IS_OPEN (v4l2camsrc);
+}
+
+/*
+ * gst_v4l2camsrc_is_active:
+ *
+ */
+static gboolean
+gst_v4l2camsrc_is_active (GstCameraSrc *camsrc)
+{
+ GstV4l2NewCamSrc *v4l2camsrc = GST_V4L2CAMSRC (camsrc);
+
+ return GST_V4L2CAMSRC_IS_ACTIVE (v4l2camsrc);
+}
+
+/*
+ * gst_v4l2camsrc_v4l2fourcc_to_structure:
+ *
+ */
+static GstStructure *
+gst_v4l2camsrc_v4l2fourcc_to_structure (guint32 fourcc)
+{
+ GstStructure *structure = NULL;
+ guint32 fcc = 0;
+
+ switch (fourcc) {
+ case V4L2_PIX_FMT_YUYV:
+ fcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ fcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
+ break;
+
+#ifdef V4L2_PIX_FMT_SBGGR8
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SBGGR16:
+ case V4L2_PIX_FMT_SGRBG10:
+ structure = gst_structure_new ("video/x-raw-bayer", NULL);
+ break;
+#endif
+ case V4L2_PIX_FMT_YUV420:
+ fcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
+ break;
+ default:
+ GST_DEBUG ("Unknown fourcc 0x%08x %" GST_FOURCC_FORMAT,
+ fourcc, GST_FOURCC_ARGS (fourcc));
+ break;
+ }
+
+ if (fcc != 0)
+ structure = gst_structure_new ("video/x-raw-yuv",
+ "format", GST_TYPE_FOURCC, fcc, NULL);
+
+ return structure;
+}
+
+/*
+ * gst_v4l2camsrc_get_caps:
+ *
+ */
+static GstCaps *
+gst_v4l2camsrc_get_caps (GstCameraSrc *camsrc)
+{
+ GstV4l2NewCamSrc *v4l2camsrc = GST_V4L2CAMSRC (camsrc);
+ GstStructure *template;
+ GstCaps *ret;
+ GSList *walk;
+
+ if (!gst_v4l2camsrc_is_open (camsrc)) {
+ /* FIXME: should it probe the device? */
+ return NULL;
+ }
+
+ if (!v4l2camsrc->formats)
+ gst_v4l2camsrc_fill_format_list (v4l2camsrc);
+
+ ret = gst_caps_new_empty ();
+
+ for (walk = v4l2camsrc->formats; walk; walk = walk->next) {
+ struct v4l2_fmtdesc *format;
+
+ /* FIXME: Introduce own format structure */
+ format = (struct v4l2_fmtdesc *) walk->data;
+
+ template = gst_v4l2camsrc_v4l2fourcc_to_structure (format->pixelformat);
+
+ if (template) {
+ GstCaps *tmp;
+
+ tmp = gst_v4l2camsrc_probe_caps_for_format (v4l2camsrc,
+ format->pixelformat, template);
+ if (tmp)
+ gst_caps_append (ret, tmp);
+
+ gst_structure_free (template);
+ } else {
+ GST_DEBUG_OBJECT (v4l2camsrc, "unknown format %u", format->pixelformat);
+ }
+ }
+
+ v4l2camsrc->probed_caps = gst_caps_ref (ret);
+
+ GST_INFO_OBJECT (v4l2camsrc, "probed caps: %" GST_PTR_FORMAT, ret);
+
+ return ret;
+}
+
+/*
+ * gst_v4l2camsrc_get_num_buffers:
+ *
+ */
+static guint
+gst_v4l2camsrc_get_num_buffers (GstCameraSrc *camsrc)
+{
+ GstV4l2NewCamSrc *v4l2camsrc = GST_V4L2CAMSRC (camsrc);
+
+ return v4l2camsrc->num_buffers;
+}
+
+
+/*
+ * gst_v4l2camsrc_base_init:
+ * @klass: #GstElementClass.
+ *
+ */
+static void
+gst_v4l2camsrc_base_init (gpointer klass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_set_details_simple (element_class,
+ "V4L2 camera source",
+ "Video/Src",
+ "Video4Linux2 camera source element",
+ "Maemo Multimedia <multimedia@maemo.org>");
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_v4l2camsrc_src_template));
+}
+
+/*
+ * gst_v4l2camsrc_class_init:
+ * @klass: #GstV4l2NewCamSrcClass.
+ *
+ */
+static void
+gst_v4l2camsrc_class_init (GstV4l2NewCamSrcClass * klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GstCameraSrcClass *camera_class = GST_CAMERA_SRC_CLASS (klass);
+
+ gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_v4l2camsrc_set_property);
+ gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_v4l2camsrc_get_property);
+ gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_v4l2camsrc_dispose);
+ gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_v4l2camsrc_finalize);
+
+ g_object_class_install_property (gobject_class, PROP_DEVICE,
+ g_param_spec_string ("device", "Device", "Device location",
+ DEFAULT_PROP_DEVICE, G_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
+ g_param_spec_string ("device-name", "Device name",
+ "Name of the device", DEFAULT_PROP_DEVICE_NAME, G_PARAM_READABLE));
+ g_object_class_install_property (gobject_class, PROP_DEVICE_FD,
+ g_param_spec_int ("device-fd", "File descriptor",
+ "File descriptor of the device", -1, G_MAXINT, DEFAULT_PROP_DEVICE_FD,
+ G_PARAM_READABLE));
+ g_object_class_install_property (gobject_class, PROP_QUEUE_SIZE,
+ g_param_spec_uint ("queue-size", "Queue size",
+ "Number of buffers to be enqueud in the driver",
+ GST_V4L2CAMSRC_MIN_BUFFERS, GST_V4L2CAMSRC_MAX_BUFFERS,
+ GST_V4L2CAMSRC_DEFAULT_BUFFERS, G_PARAM_READWRITE));
+
+ camera_class->is_open = GST_DEBUG_FUNCPTR (gst_v4l2camsrc_is_open);
+ camera_class->open = GST_DEBUG_FUNCPTR (gst_v4l2camsrc_open);
+ camera_class->close = GST_DEBUG_FUNCPTR (gst_v4l2camsrc_close);
+ camera_class->get_attribute = GST_DEBUG_FUNCPTR (gst_v4l2camsrc_get_attribute);
+ camera_class->set_attribute = GST_DEBUG_FUNCPTR (gst_v4l2camsrc_set_attribute);
+ camera_class->set_capture = GST_DEBUG_FUNCPTR (gst_v4l2camsrc_set_capture);
+ camera_class->start = GST_DEBUG_FUNCPTR (gst_v4l2camsrc_capture_start);
+ camera_class->is_active = GST_DEBUG_FUNCPTR (gst_v4l2camsrc_is_active);
+ camera_class->grab_frame = GST_DEBUG_FUNCPTR (gst_v4l2camsrc_grab_frame);
+ camera_class->stop = GST_DEBUG_FUNCPTR (gst_v4l2camsrc_capture_stop);
+ camera_class->get_caps = GST_DEBUG_FUNCPTR (gst_v4l2camsrc_get_caps);
+ camera_class->get_num_buffers = GST_DEBUG_FUNCPTR (gst_v4l2camsrc_get_num_buffers);
+ camera_class->unlock = GST_DEBUG_FUNCPTR (gst_v4l2camsrc_unlock);
+ camera_class->unlock_stop = GST_DEBUG_FUNCPTR (gst_v4l2camsrc_unlock_stop);
+}
+
+
+/*
+ * gst_v4l2camsrc_init:
+ * @v4l2camsrc: #GstV4l2NewCamSrc.
+ * @klass: #GstV4l2NewCamSrcClass.
+ *
+ */
+static void
+gst_v4l2camsrc_init (GstV4l2NewCamSrc * v4l2camsrc, GstV4l2NewCamSrcClass * klass)
+{
+ v4l2camsrc->num_buffers = GST_V4L2CAMSRC_DEFAULT_BUFFERS;
+ v4l2camsrc->tmp_num_buffers = v4l2camsrc->num_buffers;
+ v4l2camsrc->videodev = g_strdup (DEFAULT_PROP_DEVICE);
+ v4l2camsrc->video_fd = DEFAULT_PROP_DEVICE_FD;
+ v4l2camsrc->poll = gst_poll_new (TRUE);
+ v4l2camsrc->buffer = NULL;
+ v4l2camsrc->crop_supported = FALSE;
+ v4l2camsrc->max_zoom_factor = 1.0;
+
+ v4l2camsrc->device_mutex = g_mutex_new ();
+
+ GST_DEBUG ("initialized");
+}
+
+
+static void
+gst_v4l2camsrc_dispose (GObject * object)
+{
+ GstV4l2NewCamSrc *v4l2camsrc = GST_V4L2CAMSRC (object);
+
+ if (v4l2camsrc->formats) {
+ gst_v4l2camsrc_clear_format_list (v4l2camsrc);
+ }
+
+ if (v4l2camsrc->probed_caps) {
+ gst_caps_unref (v4l2camsrc->probed_caps);
+ v4l2camsrc->probed_caps = NULL;
+ }
+
+ /* FIXME: driver cleanup function */
+ if (v4l2camsrc->videodev) {
+ g_free (v4l2camsrc->videodev);
+ v4l2camsrc->videodev = NULL;
+ }
+
+ if (v4l2camsrc->poll) {
+ gst_poll_free (v4l2camsrc->poll);
+ }
+
+ g_mutex_free (v4l2camsrc->device_mutex);
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+
+/*
+ * gst_v4l2camsrc_finalize:
+ * @object:
+ *
+ */
+static void
+gst_v4l2camsrc_finalize (GObject * object)
+{
+ GstV4l2NewCamSrc *v4l2camsrc;
+
+ v4l2camsrc = GST_V4L2CAMSRC (object);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+ */
+static void
+gst_v4l2camsrc_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ GstV4l2NewCamSrc *v4l2camsrc = GST_V4L2CAMSRC (object);
+
+ switch (prop_id) {
+ case PROP_DEVICE:
+ g_free (v4l2camsrc->videodev);
+ v4l2camsrc->videodev = g_value_dup_string (value);
+ break;
+ case PROP_QUEUE_SIZE:
+ v4l2camsrc->num_buffers = g_value_get_uint (value);
+ v4l2camsrc->tmp_num_buffers = v4l2camsrc->num_buffers;
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/*
+ */
+static void
+gst_v4l2camsrc_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ GstV4l2NewCamSrc *v4l2camsrc = GST_V4L2CAMSRC (object);
+
+ switch (prop_id) {
+ case PROP_DEVICE:
+ g_value_set_string (value, v4l2camsrc->videodev);
+ break;
+ case PROP_DEVICE_NAME:
+ {
+ const guchar *new = NULL;
+
+ if (gst_v4l2camsrc_is_open (GST_CAMERA_SRC (v4l2camsrc))) {
+ new = v4l2camsrc->vcap.card;
+ } else if (gst_v4l2camsrc_open (GST_CAMERA_SRC (v4l2camsrc))) {
+ new = v4l2camsrc->vcap.card;
+ gst_v4l2camsrc_close (GST_CAMERA_SRC (v4l2camsrc));
+ gst_camerasrc_clear_color_channels (GST_CAMERA_SRC (v4l2camsrc));
+ }
+ g_value_set_string (value, (gchar *) new);
+ break;
+ }
+ case PROP_DEVICE_FD:
+ {
+ if (gst_v4l2camsrc_is_open (GST_CAMERA_SRC (v4l2camsrc)))
+ g_value_set_int (value, v4l2camsrc->video_fd);
+ else
+ g_value_set_int (value, DEFAULT_PROP_DEVICE_FD);
+ break;
+ }
+ case PROP_QUEUE_SIZE:
+ g_value_set_uint (value, v4l2camsrc->num_buffers);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+
+static gboolean
+gst_v4l2camsrc_unlock (GstCameraSrc * src)
+{
+ GstV4l2NewCamSrc *v4l2camsrc = GST_V4L2CAMSRC (src);
+
+ GST_LOG_OBJECT (v4l2camsrc, "Flushing");
+ gst_poll_set_flushing (v4l2camsrc->poll, TRUE);
+
+ return TRUE;
+}
+
+static gboolean
+gst_v4l2camsrc_unlock_stop (GstCameraSrc * src)
+{
+ GstV4l2NewCamSrc *v4l2camsrc = GST_V4L2CAMSRC (src);
+
+ GST_LOG_OBJECT (v4l2camsrc, "No longer flushing");
+ gst_poll_set_flushing (v4l2camsrc->poll, FALSE);
+
+ return TRUE;
+}
+
+
+
+
+
+
+
+
+
+/*
+ * plugin_init:
+ * @plugin: GstPlugin
+ *
+ * Returns: TRUE on success.
+ */
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ GST_DEBUG_CATEGORY_INIT (gst_v4l2camsrc_debug, "v4l2newcamsrc", 0, \
+ "V4L2 camera source");
+
+ return gst_element_register (plugin, "v4l2newcamsrc",
+ GST_RANK_NONE, GST_TYPE_V4L2CAMSRC);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "v4l2newcam",
+ "V4L2 camera image capturing element",
+ plugin_init,
+ VERSION,
+ "LGPL",
+ "Nokia", "www.nokia.com")
--- /dev/null
+/* GStreamer V4L2 camera source
+ * Copyright (C) 2010 Nokia Corporation <multimedia@maemo.org>
+ *
+ * Contact: Maemo Multimedia <multimedia@maemo.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_V4L2CAMSRC_H__
+#define __GST_V4L2CAMSRC_H__
+
+#include <linux/videodev2.h>
+
+#include <gst/gst.h>
+#include <gst/camera/gstcamerasrc.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_V4L2CAMSRC \
+(gst_v4l2camsrc_get_type())
+#define GST_V4L2CAMSRC(obj) \
+(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_V4L2CAMSRC, GstV4l2NewCamSrc))
+#define GST_V4L2CAMSRC_CLASS(klass) \
+(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_V4L2CAMSRC, GstV4l2NewCamSrcClass))
+#define GST_IS_V4L2CAMSRC(obj) \
+(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_V4L2CAMSRC))
+#define GST_IS_V4L2CAMSRC_CLASS(klass) \
+(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_V4L2CAMSRC))
+
+
+typedef struct _GstV4l2NewCamSrc GstV4l2NewCamSrc;
+typedef struct _GstV4l2NewCamSrcClass GstV4l2NewCamSrcClass;
+
+typedef struct _GstV4l2Buffer GstV4l2Buffer;
+typedef struct _GstV4l2NewCamSrcBufferPool GstV4l2NewCamSrcBufferPool;
+
+/**
+ * GstV4l2Buffer:
+ * @buffer: parent GstBuffer
+ * @pool: reference to the owning #GstV4l2NewCamSrcBufferPool
+ * @gbuffer: GstBuffer allocated for this buffer for holding the data
+ * @vbuffer: v4l2_buffer structure
+ *
+ * Opaque object.
+*/
+
+struct _GstV4l2Buffer {
+ GstBuffer buffer;
+ GstV4l2NewCamSrcBufferPool *pool;
+ GstBuffer *gbuffer;
+ void *vbuffer;
+};
+
+
+/**
+ * GstV4l2NewCamSrcBufferPool:
+ * @parent: the parent object
+ * @lock: pool lock
+ * @running: TRUE if the pool is being used
+ * @num_live_buffers: number of buffers being pushed outside element
+ * @buffer_count: total number of buffers used
+ * @buffers: buffer table
+ * @video_fd: video device which produces the buffers
+ * @queued: lookup table for buffers whether they're queued to driver
+ * @data_cond: condition being used for waiting a buffer to become available
+ *
+ * Opaque #GstV4l2NewCamSrcBufferPool object.
+ */
+struct _GstV4l2NewCamSrcBufferPool
+{
+ GstMiniObject parent;
+
+ GMutex *lock;
+ gboolean running; /* with lock */
+ gint num_live_buffers; /* number of buffers not with driver */
+ guint buffer_count;
+ GstV4l2Buffer **buffers;
+
+ gint video_fd; /* a dup(2) of the v4l2object's video_fd */
+ guint *queued;
+ GCond* data_cond;
+};
+
+/**
+* GstV4l2NewCamSrc:
+* @element: the parent element.
+*
+* The opaque #GstV4l2NewCamSrc data structure.
+*/
+struct _GstV4l2NewCamSrc {
+ GstCameraSrc element;
+
+ /*< private >*/
+ char *videodev; /* video device file name */
+ gint video_fd; /* the video-device's file descriptor */
+ GstV4l2NewCamSrcBufferPool *pool;
+ guint32 num_buffers;
+ guint32 tmp_num_buffers;
+ guint64 offset;
+ GstPoll * poll;
+ guint8 **buffer; /* the video buffer (mmap()'ed) */
+ GSList *formats; /* list of available capture formats */
+ GstCaps *probed_caps;
+ guint32 frame_byte_size;
+ GMutex *device_mutex;
+
+ guint vf_w, vf_h;
+ guint vf_fps_n, vf_fps_d;
+ guint32 vf_fourcc;
+
+ guint capture_w, capture_h;
+ guint capture_fps_n, capture_fps_d;
+ guint32 capture_fourcc;
+
+ struct v4l2_capability vcap; /* the video device's capabilities */
+ struct v4l2_cropcap vcrop; /* cropping & scaling capabilities */
+ gboolean crop_supported;
+ gfloat max_zoom_factor;
+};
+
+
+/**
+* GstV4l2NewCamSrcClass:
+* @parent_class: Element parent class.
+*
+* The opaque GstV4l2NewCamSrcClass data structure.
+*/
+struct _GstV4l2NewCamSrcClass {
+ GstCameraSrcClass parent_class;
+};
+
+GType gst_v4l2camsrc_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_V4L2CAMSRC_H__ */
\ No newline at end of file
--- /dev/null
+/* GStreamer
+ *
+ * Copyright (C) 2006 Edgard Lima <edgard.lima@indt.org.br>
+ * 2008-2010 Nokia Corporation <multimedia@maemo.org>
+ *
+ * gstv4l2vidorient.c: video orientation interface implementation for V4L2
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <linux/videodev2.h>
+#include <gst/gst.h>
+
+#include "gstv4l2camsrc.h"
+#include "v4l2camsrc_calls.h"
+#include "gstv4l2camvidorient.h"
+
+
+
+GST_DEBUG_CATEGORY_STATIC (v4l2camvo_debug);
+#define GST_CAT_DEFAULT v4l2camvo_debug
+
+/* Those are deprecated calls that have been replaced */
+#ifndef V4L2_CID_HCENTER
+#define V4L2_CID_HCENTER V4L2_CID_PAN_RESET
+#endif
+#ifndef V4L2_CID_VCENTER
+#define V4L2_CID_VCENTER V4L2_CID_TILT_RESET
+#endif
+
+void
+gst_v4l2camsrc_vo_interface_init (GstVideoOrientationInterface * klass)
+{
+ GST_DEBUG_CATEGORY_INIT (v4l2camvo_debug, "v4l2camvo", 0,
+ "V4L2 VideoOrientation interface debugging");
+}
+
+
+gboolean
+gst_v4l2camsrc_vo_get_hflip (GstV4l2NewCamSrc * v4l2camsrc,
+ gboolean * flip)
+{
+ return gst_v4l2camsrc_get_attribute (GST_CAMERA_SRC (v4l2camsrc), V4L2_CID_HFLIP, flip);
+}
+
+gboolean
+gst_v4l2camsrc_vo_get_vflip (GstV4l2NewCamSrc * v4l2camsrc,
+ gboolean * flip)
+{
+ return gst_v4l2camsrc_get_attribute (GST_CAMERA_SRC (v4l2camsrc), V4L2_CID_VFLIP, flip);
+}
+
+gboolean
+gst_v4l2camsrc_vo_get_hcenter (GstV4l2NewCamSrc * v4l2camsrc,
+ gint * center)
+{
+ return gst_v4l2camsrc_get_attribute (GST_CAMERA_SRC (v4l2camsrc), V4L2_CID_HCENTER, center);
+}
+
+gboolean
+gst_v4l2camsrc_vo_get_vcenter (GstV4l2NewCamSrc * v4l2camsrc,
+ gint * center)
+{
+ return gst_v4l2camsrc_get_attribute (GST_CAMERA_SRC (v4l2camsrc), V4L2_CID_VCENTER, center);
+}
+
+gboolean
+gst_v4l2camsrc_vo_set_hflip (GstV4l2NewCamSrc * v4l2camsrc, gboolean flip)
+{
+ return gst_v4l2camsrc_set_attribute (GST_CAMERA_SRC (v4l2camsrc), V4L2_CID_HFLIP, flip);
+}
+
+gboolean
+gst_v4l2camsrc_vo_set_vflip (GstV4l2NewCamSrc * v4l2camsrc, gboolean flip)
+{
+ return gst_v4l2camsrc_set_attribute (GST_CAMERA_SRC (v4l2camsrc), V4L2_CID_VFLIP, flip);
+}
+
+gboolean
+gst_v4l2camsrc_vo_set_hcenter (GstV4l2NewCamSrc * v4l2camsrc, gint center)
+{
+ return gst_v4l2camsrc_set_attribute (GST_CAMERA_SRC (v4l2camsrc), V4L2_CID_HCENTER, center);
+}
+
+gboolean
+gst_v4l2camsrc_vo_set_vcenter (GstV4l2NewCamSrc * v4l2camsrc, gint center)
+{
+ return gst_v4l2camsrc_set_attribute (GST_CAMERA_SRC (v4l2camsrc), V4L2_CID_VCENTER, center);
+}
--- /dev/null
+/* GStreamer
+ *
+ * Copyright (C) 2006 Edgard Lima <edgard.lima@indt.org.br>
+ * 2008-2010 Nokia Corporation <multimedia@maemo.org>
+ *
+ * gstv4l2vidorient.h: video orientation interface implementation for V4L2
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_V4L2CAMSRC_VIDORIENT_H__
+#define __GST_V4L2CAMSRC_VIDORIENT_H__
+
+#include <gst/gst.h>
+#include <gst/interfaces/videoorientation.h>
+
+#include "gstv4l2camsrc.h"
+
+
+G_BEGIN_DECLS
+
+void gst_v4l2camsrc_vo_interface_init (GstVideoOrientationInterface * klass);
+
+gboolean gst_v4l2camsrc_vo_get_hflip (GstV4l2NewCamSrc * v4l2camsrc, gboolean *flip);
+gboolean gst_v4l2camsrc_vo_get_vflip (GstV4l2NewCamSrc * v4l2camsrc, gboolean *flip);
+gboolean gst_v4l2camsrc_vo_get_hcenter (GstV4l2NewCamSrc * v4l2camsrc, gint *center);
+gboolean gst_v4l2camsrc_vo_get_vcenter (GstV4l2NewCamSrc * v4l2camsrc, gint *center);
+
+gboolean gst_v4l2camsrc_vo_set_hflip (GstV4l2NewCamSrc * v4l2camsrc, gboolean flip);
+gboolean gst_v4l2camsrc_vo_set_vflip (GstV4l2NewCamSrc * v4l2camsrc, gboolean flip);
+gboolean gst_v4l2camsrc_vo_set_hcenter (GstV4l2NewCamSrc * v4l2camsrc, gint center);
+gboolean gst_v4l2camsrc_vo_set_vcenter (GstV4l2NewCamSrc * v4l2camsrc, gint center);
+
+#define GST_IMPLEMENT_V4L2CAMSRC_VIDORIENT_METHODS(Type, interface_as_function) \
+ \
+ static gboolean \
+ interface_as_function ## _video_orientation_get_hflip (GstVideoOrientation *vo, gboolean *flip) \
+ { \
+ Type *this = (Type*) vo; \
+ return gst_v4l2camsrc_vo_get_hflip (this, flip); \
+ } \
+ \
+ static gboolean \
+ interface_as_function ## _video_orientation_get_vflip (GstVideoOrientation *vo, gboolean *flip) \
+ { \
+ Type *this = (Type*) vo; \
+ return gst_v4l2camsrc_vo_get_vflip (this, flip); \
+ } \
+ \
+ static gboolean \
+ interface_as_function ## _video_orientation_get_hcenter (GstVideoOrientation *vo, gint *center) \
+ { \
+ Type *this = (Type*) vo; \
+ return gst_v4l2camsrc_vo_get_hcenter (this, center); \
+ } \
+ \
+ static gboolean \
+ interface_as_function ## _video_orientation_get_vcenter (GstVideoOrientation *vo, gint *center) \
+ { \
+ Type *this = (Type*) vo; \
+ return gst_v4l2camsrc_vo_get_vcenter (this, center); \
+ } \
+ \
+ static gboolean \
+ interface_as_function ## _video_orientation_set_hflip (GstVideoOrientation *vo, gboolean flip) \
+ { \
+ Type *this = (Type*) vo; \
+ return gst_v4l2camsrc_vo_set_hflip (this, flip); \
+ } \
+ \
+ static gboolean \
+ interface_as_function ## _video_orientation_set_vflip (GstVideoOrientation *vo, gboolean flip) \
+ { \
+ Type *this = (Type*) vo; \
+ return gst_v4l2camsrc_vo_set_vflip (this, flip); \
+ } \
+ \
+ static gboolean \
+ interface_as_function ## _video_orientation_set_hcenter (GstVideoOrientation *vo, gint center) \
+ { \
+ Type *this = (Type*) vo; \
+ return gst_v4l2camsrc_vo_set_hcenter (this, center); \
+ } \
+ \
+ static gboolean \
+ interface_as_function ## _video_orientation_set_vcenter (GstVideoOrientation *vo, gint center) \
+ { \
+ Type *this = (Type*) vo; \
+ return gst_v4l2camsrc_vo_set_vcenter (this, center); \
+ } \
+ \
+ void \
+ interface_as_function ## _video_orientation_interface_init (GstVideoOrientationInterface * klass) \
+ { \
+ /* default virtual functions */ \
+ klass->get_hflip = interface_as_function ## _video_orientation_get_hflip; \
+ klass->get_vflip = interface_as_function ## _video_orientation_get_vflip; \
+ klass->get_hcenter = interface_as_function ## _video_orientation_get_hcenter; \
+ klass->get_vcenter = interface_as_function ## _video_orientation_get_vcenter; \
+ klass->set_hflip = interface_as_function ## _video_orientation_set_hflip; \
+ klass->set_vflip = interface_as_function ## _video_orientation_set_vflip; \
+ klass->set_hcenter = interface_as_function ## _video_orientation_set_hcenter; \
+ klass->set_vcenter = interface_as_function ## _video_orientation_set_vcenter; \
+ }
+
+#endif /* __GST_V4L2CAMSRC_VIDORIENT_H__ */
--- /dev/null
+/* GStreamer
+ *
+ * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * 2006 Edgard Lima <edgard.lima@indt.org.br>
+ * 2008-2010 Nokia Corporation <multimedia@maemo.org>
+ *
+ * v4l2camsrc.c - system calls
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <unistd.h>
+#ifdef __sun
+/* Needed on older Solaris Nevada builds (72 at least) */
+#include <stropts.h>
+#include <sys/ioccom.h>
+#endif
+
+#include <gst/camera/gstcameracolorbalance.h>
+
+#include "v4l2camsrc_calls.h"
+
+GST_DEBUG_CATEGORY_EXTERN (gst_v4l2camsrc_debug);
+#define GST_CAT_DEFAULT gst_v4l2camsrc_debug
+
+/* Define this to use memory locking for video buffers */
+/* #define USE_MLOCK */
+
+/* lalala... */
+#define GST_V4L2CAMSRC_SET_ACTIVE(element) (element)->buffer = GINT_TO_POINTER (-1)
+#define GST_V4L2CAMSRC_SET_INACTIVE(element) (element)->buffer = NULL
+
+/* On some systems MAP_FAILED seems to be missing */
+#ifndef MAP_FAILED
+#define MAP_FAILED ((caddr_t) -1)
+#endif
+
+#define RESIZER_MAX_DOWNSCALE_FACTOR 4
+#define V4L2CAMSRC_POLL_TIMEOUT (3 * GST_SECOND)
+
+#define GST_TYPE_V4L2CAMSRC_BUFFER (gst_v4l2camsrc_buffer_get_type())
+#define GST_IS_V4L2CAMSRC_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2CAMSRC_BUFFER))
+#define GST_V4L2CAMSRC_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2CAMSRC_BUFFER, GstCameraBuffer))
+
+/* Local functions */
+static gboolean
+gst_v4l2camsrc_get_nearest_size (GstV4l2NewCamSrc * v4l2camsrc, guint32 pixelformat,
+ gint * width, gint * height);
+static void gst_v4l2camsrc_buffer_pool_destroy (GstV4l2NewCamSrcBufferPool * pool,
+ GstV4l2NewCamSrc * v4l2camsrc);
+static gboolean gst_v4l2camsrc_update_cropping (GstV4l2NewCamSrc *v4l2camsrc,
+ gint width, gint height, gfloat zoom);
+
+/*
+ * GstCameraBuffer:
+ */
+
+static GstBufferClass *v4l2buffer_parent_class = NULL;
+
+static void
+gst_v4l2camsrc_buffer_finalize (GstV4l2Buffer * buffer)
+{
+ GstV4l2NewCamSrcBufferPool *pool;
+ gboolean resuscitated = FALSE;
+ struct v4l2_buffer *vbuffer;
+ gint index;
+
+ pool = buffer->pool;
+ vbuffer = (struct v4l2_buffer *) buffer->vbuffer;
+ index = vbuffer->index;
+
+ GST_LOG ("finalizing buffer %p %d", buffer, index);
+
+ g_mutex_lock (pool->lock);
+ if (GST_BUFFER_SIZE (buffer) != 0)
+ /* BUFFER_SIZE is only set if the frame was dequeued */
+ pool->num_live_buffers--;
+
+ if (pool->running) {
+ if (ioctl (pool->video_fd, VIDIOC_QBUF, vbuffer) < 0) {
+ GST_WARNING ("could not requeue buffer %p %d", buffer, index);
+ } else {
+ /* FIXME: check that the caps didn't change */
+ GST_LOG ("reviving buffer %p, %d", buffer, index);
+ gst_buffer_ref (GST_BUFFER (buffer));
+ GST_BUFFER_SIZE (buffer) = 0;
+ pool->buffers[index] = buffer;
+ pool->queued[index] = 1;
+ g_cond_signal (pool->data_cond);
+ resuscitated = TRUE;
+ }
+ } else {
+ GST_LOG ("the pool is shutting down");
+ }
+ g_mutex_unlock (pool->lock);
+
+ if (!resuscitated) {
+ GST_LOG ("buffer %p not recovered, unmapping", buffer);
+ gst_mini_object_unref (GST_MINI_OBJECT (pool));
+
+ if (buffer->gbuffer) {
+ /* It was allocated with gst_pad_alloc_buffer */
+ /* FIXME temporal fix for double free error */
+ //gst_buffer_unref (buffer->gbuffer);
+ buffer->gbuffer = NULL;
+ } else {
+ /* It was allocated with posix_memalign */
+ free (GST_BUFFER_DATA (buffer));
+ }
+ GST_BUFFER_DATA (buffer) = NULL;
+
+ g_free (buffer->vbuffer);
+
+ GST_LOG ("free v4l2buffer");
+ GST_MINI_OBJECT_CLASS (v4l2buffer_parent_class)->finalize (GST_MINI_OBJECT
+ (buffer));
+ }
+}
+
+static void
+gst_v4l2camsrc_buffer_class_init (gpointer g_class, gpointer class_data)
+{
+ GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
+
+ v4l2buffer_parent_class = g_type_class_peek_parent (g_class);
+
+ mini_object_class->finalize =
+ (GstMiniObjectFinalizeFunction) gst_v4l2camsrc_buffer_finalize;
+}
+
+static GType
+gst_v4l2camsrc_buffer_get_type (void)
+{
+ static GType _gst_v4l2camsrc_buffer_type;
+
+ if (G_UNLIKELY (_gst_v4l2camsrc_buffer_type == 0)) {
+ static const GTypeInfo v4l2camsrc_buffer_info = {
+ sizeof (GstBufferClass),
+ NULL,
+ NULL,
+ gst_v4l2camsrc_buffer_class_init,
+ NULL,
+ NULL,
+ sizeof (GstV4l2Buffer),
+ 0,
+ NULL,
+ NULL
+ };
+ _gst_v4l2camsrc_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
+ "GstCameraBuffer", &v4l2camsrc_buffer_info, 0);
+ }
+ return _gst_v4l2camsrc_buffer_type;
+}
+
+static GstV4l2Buffer *
+gst_v4l2camsrc_buffer_new (GstV4l2NewCamSrcBufferPool * pool,
+ GstV4l2NewCamSrc * v4l2camsrc, guint index, GstCaps * caps)
+{
+ GstV4l2Buffer *ret = NULL;
+ GstFlowReturn flow_ret;
+ struct v4l2_buffer *vbuffer;
+
+ ret = (GstV4l2Buffer *) gst_mini_object_new (GST_TYPE_V4L2CAMSRC_BUFFER);
+ vbuffer = ret->vbuffer = g_new0 (struct v4l2_buffer, 1);
+ GST_LOG ("creating buffer %u, %p in pool %p", index, ret, pool);
+ ret->pool =
+ (GstV4l2NewCamSrcBufferPool *) gst_mini_object_ref (GST_MINI_OBJECT (pool));
+
+ vbuffer->index = index;
+ vbuffer->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ vbuffer->memory = V4L2_MEMORY_USERPTR;
+ vbuffer->length = v4l2camsrc->frame_byte_size;
+ ret->gbuffer = NULL;
+
+ if (ioctl (pool->video_fd, VIDIOC_QUERYBUF, vbuffer) < 0)
+ goto querybuf_failed;
+
+ if (gst_pad_is_linked (GST_BASE_SRC_PAD (v4l2camsrc))) {
+ GST_LOG ("using pad_alloc, size=%d", v4l2camsrc->frame_byte_size);
+ GST_LOG ("ALLOC CAPS: %" GST_PTR_FORMAT, caps);
+
+ flow_ret = gst_pad_alloc_buffer_and_set_caps (GST_BASE_SRC_PAD (v4l2camsrc),
+ 0LL, v4l2camsrc->frame_byte_size, caps, &ret->gbuffer);
+ if (flow_ret != GST_FLOW_OK)
+ goto pad_alloc_failed;
+ GST_BUFFER_DATA (ret) = ret->gbuffer->data;
+ }
+ else {
+ void *data;
+
+ GST_LOG ("using posix_memalign");
+ if (posix_memalign (&data, getpagesize(), vbuffer->length) != 0) {
+ goto memalign_failed;
+ }
+ GST_BUFFER_DATA (ret) = (guint8 *) data;
+ }
+
+ GST_BUFFER_SIZE (ret) = vbuffer->length;
+ GST_BUFFER_FLAG_SET (ret, GST_BUFFER_FLAG_READONLY);
+ gst_buffer_set_caps (GST_BUFFER (ret), caps);
+
+#ifdef USE_MLOCK
+ GST_DEBUG ("mlocking buffer data");
+ if (mlock ((void *) GST_BUFFER_DATA (ret), v4l2camsrc->frame_byte_size) == -1)
+ goto mlock_failed;
+#endif
+
+ /* mlocking succeeded, now we can set the pointer to vbuffer. The existence
+ * of this pointer will be used later to determine if the munlock() is
+ * needed */
+ vbuffer->m.userptr = (unsigned int) GST_BUFFER_DATA (ret);
+
+#if 1
+ GST_LOG (" index: %u", vbuffer->index);
+ GST_LOG (" type: %d", vbuffer->type);
+ GST_LOG (" bytesused: %u", vbuffer->bytesused);
+ GST_LOG (" flags: %08x", vbuffer->flags);
+ GST_LOG (" field: %d", vbuffer->field);
+ GST_LOG (" memory: %d", vbuffer->memory);
+ if (vbuffer->memory == V4L2_MEMORY_MMAP)
+ GST_LOG (" MMAP offset: %u", vbuffer->m.offset);
+ else if (vbuffer->memory == V4L2_MEMORY_USERPTR)
+ GST_LOG (" user address: %u", vbuffer->m.userptr);
+ GST_LOG (" length: %u", vbuffer->length);
+ GST_LOG (" input: %u", vbuffer->input);
+#endif
+
+ return ret;
+
+ /* ERRORS */
+#ifdef USE_MLOCK
+mlock_failed:
+ {
+ GST_WARNING ("Failed to mlock memory: %s", g_strerror (errno));
+ gst_buffer_unref (GST_BUFFER (ret));
+ g_free (vbuffer);
+ return NULL;
+ }
+#endif
+querybuf_failed:
+ {
+ gint errnosave = errno;
+
+ GST_WARNING ("Failed QUERYBUF: %s", g_strerror (errnosave));
+ gst_buffer_unref (GST_BUFFER (ret));
+ g_free (vbuffer);
+ errno = errnosave;
+ return NULL;
+ }
+memalign_failed:
+ {
+ GST_WARNING ("Failed to posix_memalign a buffer");
+ g_free (vbuffer);
+ return NULL;
+ }
+pad_alloc_failed:
+ {
+ GST_WARNING ("Failed to pad_alloc_buffer: %s",
+ gst_flow_get_name (flow_ret));
+ g_free (vbuffer);
+ return NULL;
+ }
+}
+
+
+#define GST_TYPE_V4L2CAMSRC_BUFFER_POOL (gst_v4l2camsrc_buffer_pool_get_type())
+#define GST_IS_V4L2CAMSRC_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2CAMSRC_BUFFER_POOL))
+#define GST_V4L2CAMSRC_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2CAMSRC_BUFFER_POOL, GstV4l2NewCamSrcBufferPool))
+
+static GstMiniObjectClass *buffer_pool_parent_class = NULL;
+
+static void
+gst_v4l2camsrc_buffer_pool_finalize (GstV4l2NewCamSrcBufferPool * pool)
+{
+ g_mutex_free (pool->lock);
+ pool->lock = NULL;
+
+ if (pool->video_fd >= 0)
+ close (pool->video_fd);
+
+ if (pool->buffers) {
+ g_free (pool->buffers);
+ pool->buffers = NULL;
+ }
+
+ if (pool->queued) {
+ g_free (pool->queued);
+ pool->queued = NULL;
+ }
+
+ g_cond_free (pool->data_cond);
+ pool->data_cond = NULL;
+
+ GST_MINI_OBJECT_CLASS (buffer_pool_parent_class)->finalize (GST_MINI_OBJECT
+ (pool));
+}
+
+/*
+ */
+static void
+gst_v4l2camsrc_buffer_pool_init (GstV4l2NewCamSrcBufferPool * pool,
+ gpointer g_class)
+{
+ pool->lock = g_mutex_new ();
+ pool->running = FALSE;
+ pool->num_live_buffers = 0;
+ pool->data_cond = g_cond_new();
+}
+
+/*
+ */
+static void
+gst_v4l2camsrc_buffer_pool_class_init (gpointer g_class, gpointer class_data)
+{
+ GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
+
+ buffer_pool_parent_class = g_type_class_peek_parent (g_class);
+
+ mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
+ gst_v4l2camsrc_buffer_pool_finalize;
+}
+
+/*
+ */
+static GType
+gst_v4l2camsrc_buffer_pool_get_type (void)
+{
+ static GType _gst_v4l2camsrc_buffer_pool_type;
+
+ if (G_UNLIKELY (_gst_v4l2camsrc_buffer_pool_type == 0)) {
+ static const GTypeInfo v4l2camsrc_buffer_pool_info = {
+ sizeof (GstBufferClass),
+ NULL,
+ NULL,
+ gst_v4l2camsrc_buffer_pool_class_init,
+ NULL,
+ NULL,
+ sizeof (GstV4l2NewCamSrcBufferPool),
+ 0,
+ (GInstanceInitFunc) gst_v4l2camsrc_buffer_pool_init,
+ NULL
+ };
+ _gst_v4l2camsrc_buffer_pool_type = g_type_register_static (GST_TYPE_MINI_OBJECT,
+ "GstV4l2NewCamSrcBufferPool", &v4l2camsrc_buffer_pool_info, 0);
+ }
+ return _gst_v4l2camsrc_buffer_pool_type;
+}
+
+/*
+ */
+static GstV4l2NewCamSrcBufferPool *
+gst_v4l2camsrc_buffer_pool_new (GstV4l2NewCamSrc * v4l2camsrc, gint fd,
+ GstCaps * caps)
+{
+ GstV4l2NewCamSrcBufferPool *pool;
+ gint n;
+
+ pool = (GstV4l2NewCamSrcBufferPool *)
+ gst_mini_object_new (GST_TYPE_V4L2CAMSRC_BUFFER_POOL);
+
+ pool->video_fd = dup (fd);
+ if (pool->video_fd < 0)
+ goto dup_failed;
+
+
+ pool->buffer_count = v4l2camsrc->num_buffers;
+ pool->buffers = g_new0 (GstV4l2Buffer *, pool->buffer_count);
+ pool->queued = g_new0 (guint, pool->buffer_count);
+
+ for (n = 0; n < pool->buffer_count; n++) {
+ pool->buffers[n] = gst_v4l2camsrc_buffer_new (pool, v4l2camsrc, n, caps);
+ GST_LOG ("buffer ref is %d", GST_MINI_OBJECT_REFCOUNT(pool->buffers[n]));
+ if (!pool->buffers[n])
+ goto buffer_new_failed;
+ }
+
+ return pool;
+
+ /* ERRORS */
+dup_failed:
+ {
+ gint errnosave = errno;
+
+ gst_v4l2camsrc_buffer_pool_destroy (pool, v4l2camsrc);
+
+ errno = errnosave;
+
+ return NULL;
+ }
+buffer_new_failed:
+ {
+ gint errnosave = errno;
+
+ GST_LOG ("creating a new buffer failed");
+ gst_mini_object_unref (GST_MINI_OBJECT (pool));
+
+ errno = errnosave;
+
+ return NULL;
+ }
+}
+
+/*
+ */
+static gboolean
+gst_v4l2camsrc_buffer_pool_activate (GstV4l2NewCamSrcBufferPool * pool,
+ GstV4l2NewCamSrc * v4l2camsrc)
+{
+ gint n;
+
+ g_mutex_lock (pool->lock);
+
+ for (n = 0; n < pool->buffer_count; n++) {
+
+ struct v4l2_buffer *buf;
+
+ buf = (struct v4l2_buffer *) pool->buffers[n]->vbuffer;
+
+ GST_LOG ("enqueue pool buffer %d", n);
+
+ if (ioctl (pool->video_fd, VIDIOC_QBUF, buf) < 0)
+ goto queue_failed;
+
+ pool->queued[n] = 1;
+ }
+ pool->running = TRUE;
+
+ g_mutex_unlock (pool->lock);
+
+ return TRUE;
+
+ /* ERRORS */
+queue_failed:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, READ,
+ ("Could not enqueue buffers in device '%s'.",
+ v4l2camsrc->videodev),
+ ("enqueing buffer %d/%d failed: %s",
+ n, v4l2camsrc->num_buffers, g_strerror (errno)));
+ g_mutex_unlock (pool->lock);
+ return FALSE;
+ }
+}
+
+#if 0
+/* requeue buffers that are writable again */
+/* FIXME: This isn't needed anymore. Buffers are re-queued automatically
+ * when they are finalized, so there is no need to wait for them separately */
+static gboolean
+gst_v4l2_buffer_pool_update (GstV4l2NewCamSrcBufferPool * pool,
+ GstV4l2NewCamSrc * v4l2camsrc)
+{
+ gint n;
+ gint ref=0;
+
+ g_mutex_lock (pool->lock);
+
+ for (n = 0; n < pool->buffer_count; n++) {
+ if (!pool->queued[n]) {
+ GST_LOG ("buffer %d is dequeued", n);
+ ref++;
+ }
+ }
+
+ /* if all the buffers are dequeued, wait */
+ if (ref == GST_CAMERA_SRC (v4l2camsrc)->num_buffers) {
+ GST_LOG ("no free buffers available");
+ g_cond_wait (pool->data_cond, pool->lock);
+ }
+
+ g_mutex_unlock (pool->lock);
+
+ return (ref != GST_CAMERA_SRC (v4l2camsrc)->num_buffers) ? TRUE : FALSE;
+}
+#endif
+
+/*
+ */
+static void
+gst_v4l2camsrc_buffer_pool_destroy (GstV4l2NewCamSrcBufferPool * pool,
+ GstV4l2NewCamSrc * v4l2camsrc)
+{
+ gint n;
+
+ g_mutex_lock (pool->lock);
+ pool->running = FALSE;
+ g_mutex_unlock (pool->lock);
+
+ GST_DEBUG ("destroy pool");
+
+ /* after this point, no more buffers will be queued or dequeued; no buffer
+ * from pool->buffers that is NULL will be set to a buffer, and no buffer that
+ * is not NULL will be pushed out. */
+
+ /* miniobjects have no dispose, so they can't break ref-cycles, as buffers ref
+ * the pool, we need to unref the buffer to properly finalize te pool */
+ for (n = 0; n < pool->buffer_count; n++) {
+ GstBuffer *buf;
+
+ g_mutex_lock (pool->lock);
+ buf = GST_BUFFER (pool->buffers[n]);
+ g_mutex_unlock (pool->lock);
+
+ if (buf) {
+#ifdef USE_MLOCK
+ if (pool->buffers[n].m.userptr) {
+ GST_DEBUG ("munlocking buffer data");
+ munlock ((void *)pool->buffers[n].m.userptr,
+ v4l2camsrc->frame_byte_size);
+ }
+#endif
+ /* we own the ref if the buffer is in pool->buffers; drop it. */
+ gst_buffer_unref (buf);
+ }
+ }
+
+ gst_mini_object_unref (GST_MINI_OBJECT (pool));
+}
+
+/******************************************************
+ * gst_v4l2camsrc_get_capabilities():
+ * get the device's capturing capabilities
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+static gboolean
+gst_v4l2camsrc_get_capabilities (GstV4l2NewCamSrc *v4l2camsrc)
+{
+ GST_DEBUG_OBJECT (v4l2camsrc, "getting capabilities");
+
+ if (!GST_V4L2CAMSRC_IS_OPEN (v4l2camsrc))
+ return FALSE;
+
+ if (ioctl (v4l2camsrc->video_fd, VIDIOC_QUERYCAP, &v4l2camsrc->vcap) < 0)
+ goto cap_failed;
+
+ GST_LOG_OBJECT (v4l2camsrc, "driver: '%s'", v4l2camsrc->vcap.driver);
+ GST_LOG_OBJECT (v4l2camsrc, "card: '%s'", v4l2camsrc->vcap.card);
+ GST_LOG_OBJECT (v4l2camsrc, "bus_info: '%s'", v4l2camsrc->vcap.bus_info);
+ GST_LOG_OBJECT (v4l2camsrc, "version: %08x", v4l2camsrc->vcap.version);
+ GST_LOG_OBJECT (v4l2camsrc, "capabilites: %08x", v4l2camsrc->vcap.capabilities);
+
+ return TRUE;
+
+ /* ERRORS */
+cap_failed:
+{
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, SETTINGS,
+ ("Error getting capabilities for device '%s': "
+ "It isn't a v4l2 driver. Check if it is a v4l1 driver.",
+ v4l2camsrc->videodev), GST_ERROR_SYSTEM);
+ return FALSE;
+}
+}
+
+
+/******************************************************
+ * gst_v4l2camsrc_fill_lists():
+ * fill the lists of enumerations
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+static gboolean
+gst_v4l2camsrc_fill_lists (GstV4l2NewCamSrc *v4l2camsrc)
+{
+ gint n;
+
+ GST_DEBUG_OBJECT (v4l2camsrc, "getting enumerations");
+ GST_V4L2CAMSRC_CHECK_OPEN (v4l2camsrc);
+
+ GST_DEBUG_OBJECT (v4l2camsrc, " controls+menus");
+ /* and lastly, controls+menus (if appropriate) */
+ for (n = V4L2_CID_BASE;; n++) {
+ struct v4l2_queryctrl control = { 0, };
+ GstCameraSrcColorBalanceChannel *v4l2channel;
+
+ GstColorBalanceChannel *channel;
+
+ /* when we reached the last official CID, continue with private CIDs */
+ if (n == V4L2_CID_LASTP1) {
+ GST_DEBUG_OBJECT (v4l2camsrc, "checking private CIDs");
+ n = V4L2_CID_PRIVATE_BASE;
+ /* FIXME: We are still not handling private controls. We need a
+ new GstInterface to export those controls */
+ break;
+ }
+
+ control.id = n;
+ if (ioctl (v4l2camsrc->video_fd, VIDIOC_QUERYCTRL, &control) < 0) {
+ if (errno == EINVAL) {
+ if (n < V4L2_CID_PRIVATE_BASE)
+ /* continue so that we also check private controls */
+ continue;
+ else
+ break;
+ } else {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, SETTINGS,
+ ("Failed getting controls attributes on device '%s.'",
+ v4l2camsrc->videodev),
+ ("Failed querying control %d on device '%s'. (%d - %s)",
+ n, v4l2camsrc->videodev, errno, strerror (errno)));
+ return FALSE;
+ }
+ }
+ if (control.flags & V4L2_CTRL_FLAG_DISABLED)
+ continue;
+
+ switch (n) {
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ case V4L2_CID_BLACK_LEVEL:
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ case V4L2_CID_DO_WHITE_BALANCE:
+ case V4L2_CID_RED_BALANCE:
+ case V4L2_CID_BLUE_BALANCE:
+ case V4L2_CID_GAMMA:
+ case V4L2_CID_EXPOSURE:
+ case V4L2_CID_AUTOGAIN:
+ case V4L2_CID_GAIN:
+ /* we only handle these for now (why?) */
+ break;
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ case V4L2_CID_HCENTER:
+ case V4L2_CID_VCENTER:
+#ifdef V4L2_CID_PAN_RESET
+ case V4L2_CID_PAN_RESET:
+#endif
+#ifdef V4L2_CID_TILT_RESET
+ case V4L2_CID_TILT_RESET:
+#endif
+ /* not handled here, handled by VideoOrientation interface */
+ control.id++;
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+ /* FIXME: We should implement GstMixer interface */
+ /* fall through */
+ default:
+ GST_DEBUG_OBJECT (v4l2camsrc,
+ "ControlID %s (%x) unhandled, FIXME", control.name, n);
+ control.id++;
+ break;
+ }
+ if (n != control.id)
+ continue;
+
+ GST_DEBUG_OBJECT (v4l2camsrc, "Adding ControlID %s (%x)", control.name, n);
+ v4l2channel = g_object_new (GST_TYPE_CAMERA_SRC_COLOR_BALANCE_CHANNEL, NULL);
+ channel = GST_COLOR_BALANCE_CHANNEL (v4l2channel);
+ channel->label = g_strdup ((const gchar *) control.name);
+ v4l2channel->id = n;
+
+ switch (control.type) {
+ case V4L2_CTRL_TYPE_INTEGER:
+ channel->min_value = control.minimum;
+ channel->max_value = control.maximum;
+ break;
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ channel->min_value = FALSE;
+ channel->max_value = TRUE;
+ break;
+ default:
+ /* FIXME we should find out how to handle V4L2_CTRL_TYPE_BUTTON.
+ BUTTON controls like V4L2_CID_DO_WHITE_BALANCE can just be set (1) or
+ unset (0), but can't be queried */
+ GST_DEBUG_OBJECT (v4l2camsrc,
+ "Control with non supported type %s (%x), type=%d",
+ control.name, n, control.type);
+ channel->min_value = channel->max_value = 0;
+ break;
+ }
+
+ gst_camerasrc_add_color_channel (GST_CAMERA_SRC (v4l2camsrc), channel);
+ }
+
+ GST_DEBUG_OBJECT (v4l2camsrc, "done");
+ return TRUE;
+}
+
+/******************************************************
+ * gst_v4l2camsrc_open():
+ * open the video device (v4l2camsrc->videodev)
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+gboolean
+gst_v4l2camsrc_open (GstCameraSrc *camsrc)
+{
+ struct stat st;
+ GstPollFD pollfd = GST_POLL_FD_INIT;
+
+ GstV4l2NewCamSrc *v4l2camsrc = GST_V4L2CAMSRC (camsrc);
+
+ GST_DEBUG_OBJECT (v4l2camsrc, "Trying to open device %s",
+ v4l2camsrc->videodev);
+
+ GST_V4L2CAMSRC_CHECK_NOT_OPEN (v4l2camsrc);
+ GST_V4L2CAMSRC_CHECK_NOT_ACTIVE (v4l2camsrc);
+
+ /* be sure we have a device */
+ if (!v4l2camsrc->videodev)
+ v4l2camsrc->videodev = g_strdup ("/dev/video");
+
+ /* check if it is a device */
+ if (stat (v4l2camsrc->videodev, &st) == -1)
+ goto stat_failed;
+
+ if (!S_ISCHR (st.st_mode))
+ goto no_device;
+
+ /* open the device */
+ v4l2camsrc->video_fd =
+ open (v4l2camsrc->videodev, O_RDWR /* | O_NONBLOCK */ );
+
+ if (!GST_V4L2CAMSRC_IS_OPEN (v4l2camsrc))
+ goto not_open;
+
+ /* get capabilities, error will be posted */
+ if (!gst_v4l2camsrc_get_capabilities (v4l2camsrc))
+ goto error;
+
+ /* do we need to be a capture device? */
+ if (GST_IS_V4L2CAMSRC (v4l2camsrc) &&
+ !(v4l2camsrc->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
+ goto not_capture;
+
+ /* Before iterating enumerations, clear the parent's color channel list */
+ gst_camerasrc_clear_color_channels (camsrc);
+
+ /* create enumerations, posts errors. */
+ if (!gst_v4l2camsrc_fill_lists (v4l2camsrc))
+ goto error;
+
+ GST_INFO_OBJECT (v4l2camsrc,
+ "Opened device '%s' (%s) successfully",
+ v4l2camsrc->vcap.card, v4l2camsrc->videodev);
+
+ pollfd.fd = v4l2camsrc->video_fd;
+ gst_poll_add_fd (v4l2camsrc->poll, &pollfd);
+ gst_poll_fd_ctl_read (v4l2camsrc->poll, &pollfd, TRUE);
+
+ return TRUE;
+
+ /* ERRORS */
+stat_failed:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, NOT_FOUND,
+ ("Cannot identify device '%s'.", v4l2camsrc->videodev),
+ GST_ERROR_SYSTEM);
+ goto error;
+ }
+no_device:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, NOT_FOUND,
+ ("This isn't a device '%s'.", v4l2camsrc->videodev),
+ GST_ERROR_SYSTEM);
+ goto error;
+ }
+not_open:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, OPEN_READ_WRITE,
+ ("Could not open device '%s' for reading and writing.",
+ v4l2camsrc->videodev), GST_ERROR_SYSTEM);
+ goto error;
+ }
+not_capture:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, NOT_FOUND,
+ ("Device '%s' is not a capture device.",
+ v4l2camsrc->videodev),
+ ("Capabilities: 0x%x", v4l2camsrc->vcap.capabilities));
+ goto error;
+ }
+error:
+ {
+ if (GST_V4L2CAMSRC_IS_OPEN (v4l2camsrc)) {
+ /* close device */
+ close (v4l2camsrc->video_fd);
+ v4l2camsrc->video_fd = -1;
+ }
+
+ return FALSE;
+ }
+}
+
+/******************************************************
+ * gst_v4l2camsrc_close():
+ * close the video device (v4l2camsrc->video_fd)
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+gboolean
+gst_v4l2camsrc_close (GstCameraSrc *camsrc)
+{
+ GstV4l2NewCamSrc *v4l2camsrc = GST_V4L2CAMSRC (camsrc);
+
+ GstPollFD pollfd = GST_POLL_FD_INIT;
+
+ GST_DEBUG_OBJECT (v4l2camsrc, "Trying to close %s",
+ v4l2camsrc->videodev);
+
+ GST_V4L2CAMSRC_CHECK_OPEN (v4l2camsrc);
+ GST_V4L2CAMSRC_CHECK_NOT_ACTIVE (v4l2camsrc);
+
+ /* close device */
+ close (v4l2camsrc->video_fd);
+ pollfd.fd = v4l2camsrc->video_fd;
+ gst_poll_remove_fd (v4l2camsrc->poll, &pollfd);
+ v4l2camsrc->video_fd = -1;
+
+ return TRUE;
+}
+
+/******************************************************
+ * gst_v4l2camsrc_get_attribute():
+ * try to get the value of one specific attribute
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+gboolean
+gst_v4l2camsrc_get_attribute (GstCameraSrc *camsrc,
+ int attribute_num, int *value)
+{
+ GstV4l2NewCamSrc *v4l2camsrc = GST_V4L2CAMSRC (camsrc);
+
+ struct v4l2_control control;
+
+ GST_DEBUG_OBJECT (v4l2camsrc, "getting value of attribute %d",
+ attribute_num);
+
+ if (!GST_V4L2CAMSRC_IS_OPEN (v4l2camsrc))
+ return FALSE;
+
+ control.id = attribute_num;
+
+ if (ioctl (v4l2camsrc->video_fd, VIDIOC_G_CTRL, &control) < 0)
+ goto ctrl_failed1;
+
+ *value = control.value;
+
+ return TRUE;
+
+ctrl_failed1:
+{
+ struct v4l2_ext_controls controls;
+ struct v4l2_ext_control control;
+
+ controls.ctrl_class = V4L2_CTRL_CLASS_USER;
+ controls.count = 1;
+ controls.controls = &control;
+
+ control.id = attribute_num;
+
+ if (ioctl (v4l2camsrc->video_fd, VIDIOC_G_EXT_CTRLS, &controls) < 0)
+ goto ctrl_failed2;
+
+ *value = control.value;
+
+ return TRUE;
+
+}
+
+ /* ERRORS */
+ctrl_failed2:
+{
+ GST_ELEMENT_WARNING (v4l2camsrc, RESOURCE, SETTINGS,
+ ("Failed to get value for control %d on device '%s'.",
+ attribute_num, v4l2camsrc->videodev), GST_ERROR_SYSTEM);
+ return FALSE;
+}
+}
+
+/******************************************************
+ * gst_v4l2camsrc_set_attribute():
+ * try to set the value of one specific attribute
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+gboolean
+gst_v4l2camsrc_set_attribute (GstCameraSrc *camsrc,
+ int attribute_num, const int value)
+{
+ GstV4l2NewCamSrc *v4l2camsrc = GST_V4L2CAMSRC (camsrc);
+
+ struct v4l2_control control;
+
+ GST_DEBUG_OBJECT (v4l2camsrc, "setting value of attribute %d to %d",
+ attribute_num, value);
+
+ if (!GST_V4L2CAMSRC_IS_OPEN (v4l2camsrc))
+ return FALSE;
+
+ control.id = attribute_num;
+ control.value = value;
+ if (ioctl (v4l2camsrc->video_fd, VIDIOC_S_CTRL, &control) < 0)
+ goto ctrl_failed1;
+
+ return TRUE;
+
+ctrl_failed1:
+{
+ struct v4l2_ext_controls controls;
+ struct v4l2_ext_control control;
+
+ controls.ctrl_class = V4L2_CTRL_CLASS_USER;
+ controls.count = 1;
+ controls.controls = &control;
+
+ control.id = attribute_num;
+ control.value = value;
+
+ if (ioctl (v4l2camsrc->video_fd, VIDIOC_S_EXT_CTRLS, &controls) < 0)
+ goto ctrl_failed2;
+
+ return TRUE;
+}
+
+ /* ERRORS */
+ctrl_failed2:
+{
+ GST_ELEMENT_WARNING (v4l2camsrc, RESOURCE, SETTINGS,
+ ("Failed to set value %d for control %d on device '%s'.",
+ value, attribute_num, v4l2camsrc->videodev), GST_ERROR_SYSTEM);
+ return FALSE;
+}
+}
+
+
+/* complete made up ranking, the values themselves are meaningless */
+#define YUV_BASE_RANK 1000
+#define BAYER_BASE_RANK 15
+
+static gint
+gst_v4l2camsrc_format_get_rank (guint32 fourcc)
+{
+ switch (fourcc) {
+
+ case V4L2_PIX_FMT_YUYV: /* YUY2, 16 bits per pixel */
+ return YUV_BASE_RANK + 10;
+ case V4L2_PIX_FMT_UYVY: /* UYVY, 16 bits per pixel */
+ return YUV_BASE_RANK + 9;
+ case V4L2_PIX_FMT_YUV420:
+ return YUV_BASE_RANK + 7;
+
+#ifdef V4L2_PIX_FMT_SGRBG10
+ case V4L2_PIX_FMT_SGRBG10:
+#endif
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SBGGR16:
+ return BAYER_BASE_RANK;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static gint
+gst_v4l2camsrc_format_cmp_func (gconstpointer a, gconstpointer b)
+{
+ guint32 pf1 = ((struct v4l2_fmtdesc *) a)->pixelformat;
+ guint32 pf2 = ((struct v4l2_fmtdesc *) b)->pixelformat;
+
+ if (pf1 == pf2)
+ return 0;
+
+ return gst_v4l2camsrc_format_get_rank (pf2) -
+ gst_v4l2camsrc_format_get_rank (pf1);
+}
+
+/******************************************************
+ * gst_v4l2camsrc_fill_format_list():
+ * create list of supported capture formats
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+gboolean
+gst_v4l2camsrc_fill_format_list (GstV4l2NewCamSrc *v4l2camsrc)
+{
+ gint n;
+ struct v4l2_fmtdesc *format;
+
+ GST_DEBUG_OBJECT (v4l2camsrc, "getting src format enumerations");
+
+ /* format enumeration */
+ for (n = 0;; n++) {
+ format = g_new0 (struct v4l2_fmtdesc, 1);
+
+ format->index = n;
+ format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if (ioctl (v4l2camsrc->video_fd, VIDIOC_ENUM_FMT, format) < 0) {
+ if (errno == EINVAL) {
+ g_free (format);
+ break; /* end of enumeration */
+ } else {
+ goto failed;
+ }
+ }
+
+ GST_LOG_OBJECT (v4l2camsrc, "index: %u", format->index);
+ GST_LOG_OBJECT (v4l2camsrc, "type: %d", format->type);
+ GST_LOG_OBJECT (v4l2camsrc, "flags: %08x", format->flags);
+ GST_LOG_OBJECT (v4l2camsrc, "description: '%s'", format->description);
+ GST_LOG_OBJECT (v4l2camsrc, "pixelformat: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (format->pixelformat));
+
+ /* sort formats according to our preference; we do this, because caps
+ * are probed in the order the formats are in the list, and the order of
+ * formats in the final probed caps matters for things like fixation */
+ v4l2camsrc->formats = g_slist_insert_sorted (v4l2camsrc->formats, format,
+ (GCompareFunc) gst_v4l2camsrc_format_cmp_func);
+ }
+
+ GST_DEBUG_OBJECT (v4l2camsrc, "got %d format(s)", n);
+
+ return TRUE;
+
+ /* ERRORS */
+failed:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, SETTINGS,
+ ("Failed to enumerate possible video formats device '%s' can work with",
+ v4l2camsrc->videodev),
+ ("Failed to get number %d in pixelformat enumeration for %s. (%d - %s)",
+ n, v4l2camsrc->videodev, errno, g_strerror (errno)));
+ g_free (format);
+ return FALSE;
+ }
+}
+
+/******************************************************
+ * gst_v4l2camsrc_clear_format_list():
+ * free list of supported capture formats
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+gboolean
+gst_v4l2camsrc_clear_format_list (GstV4l2NewCamSrc *v4l2camsrc)
+{
+ g_slist_foreach (v4l2camsrc->formats, (GFunc) g_free, NULL);
+ g_slist_free (v4l2camsrc->formats);
+ v4l2camsrc->formats = NULL;
+
+ return TRUE;
+}
+
+/* The frame interval enumeration code first appeared in Linux 2.6.19. */
+#ifdef VIDIOC_ENUM_FRAMEINTERVALS
+static GstStructure *
+gst_v4l2camsrc_probe_caps_for_format_and_size (GstV4l2NewCamSrc * v4l2camsrc,
+ guint32 pixelformat,
+ guint32 width, guint32 height, const GstStructure * template)
+{
+ gint fd = v4l2camsrc->video_fd;
+ struct v4l2_frmivalenum ival;
+ guint32 num, denom;
+ GstStructure *s;
+ GValue rates = { 0, };
+
+ memset (&ival, 0, sizeof (struct v4l2_frmivalenum));
+ ival.index = 0;
+ ival.pixel_format = pixelformat;
+ ival.width = width;
+ ival.height = height;
+
+ GST_LOG_OBJECT (v4l2camsrc, "get frame interval for %ux%u, %"
+ GST_FOURCC_FORMAT, width, height, GST_FOURCC_ARGS (pixelformat));
+
+ /* keep in mind that v4l2 gives us frame intervals (durations); we invert the
+ * fraction to get framerate */
+ if (ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0)
+ goto enum_frameintervals_failed;
+
+ if (ival.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
+ GValue rate = { 0, };
+
+ g_value_init (&rates, GST_TYPE_LIST);
+ g_value_init (&rate, GST_TYPE_FRACTION);
+
+ do {
+ num = ival.discrete.numerator;
+ denom = ival.discrete.denominator;
+
+ if (num > G_MAXINT || denom > G_MAXINT) {
+ /* let us hope we don't get here... */
+ num >>= 1;
+ denom >>= 1;
+ }
+
+ GST_LOG_OBJECT (v4l2camsrc, "adding discrete framerate: %d/%d",
+ denom, num);
+
+ /* swap to get the framerate */
+ gst_value_set_fraction (&rate, denom, num);
+ gst_value_list_append_value (&rates, &rate);
+
+ ival.index++;
+ } while (ioctl (fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) >= 0);
+ } else if (ival.type == V4L2_FRMIVAL_TYPE_STEPWISE) {
+ GValue min = { 0, };
+ GValue step = { 0, };
+ GValue max = { 0, };
+ gboolean added = FALSE;
+ guint32 minnum, mindenom;
+ guint32 maxnum, maxdenom;
+
+ g_value_init (&rates, GST_TYPE_LIST);
+
+ g_value_init (&min, GST_TYPE_FRACTION);
+ g_value_init (&step, GST_TYPE_FRACTION);
+ g_value_init (&max, GST_TYPE_FRACTION);
+
+ /* get the min */
+ minnum = ival.stepwise.min.numerator;
+ mindenom = ival.stepwise.min.denominator;
+ if (minnum > G_MAXINT || mindenom > G_MAXINT) {
+ minnum >>= 1;
+ mindenom >>= 1;
+ }
+ GST_LOG_OBJECT (v4l2camsrc, "stepwise min frame interval: %d/%d", minnum,
+ mindenom);
+ gst_value_set_fraction (&min, minnum, mindenom);
+
+ /* get the max */
+ maxnum = ival.stepwise.max.numerator;
+ maxdenom = ival.stepwise.max.denominator;
+ if (maxnum > G_MAXINT || maxdenom > G_MAXINT) {
+ maxnum >>= 1;
+ maxdenom >>= 1;
+ }
+
+ GST_LOG_OBJECT (v4l2camsrc, "stepwise max frame interval: %d/%d", maxnum,
+ maxdenom);
+ gst_value_set_fraction (&max, maxnum, maxdenom);
+
+ /* get the step */
+ num = ival.stepwise.step.numerator;
+ denom = ival.stepwise.step.denominator;
+ if (num > G_MAXINT || denom > G_MAXINT) {
+ num >>= 1;
+ denom >>= 1;
+ }
+
+ if (num == 0 || denom == 0) {
+ /* in this case we have a wrong fraction or no step, set the step to max
+ * so that we only add the min value in the loop below */
+ num = maxnum;
+ denom = maxdenom;
+ }
+
+ /* since we only have gst_value_fraction_subtract and not add, negate the
+ * numerator */
+ GST_LOG_OBJECT (v4l2camsrc, "stepwise step frame interval: %d/%d",
+ num, denom);
+
+ gst_value_set_fraction (&step, -num, denom);
+
+ while (gst_value_compare (&min, &max) <= 0) {
+ GValue rate = { 0, };
+
+ num = gst_value_get_fraction_numerator (&min);
+ denom = gst_value_get_fraction_denominator (&min);
+ GST_LOG_OBJECT (v4l2camsrc, "adding stepwise framerate: %d/%d",
+ denom, num);
+
+ /* invert to get the framerate */
+ g_value_init (&rate, GST_TYPE_FRACTION);
+ gst_value_set_fraction (&rate, denom, num);
+ gst_value_list_append_value (&rates, &rate);
+ added = TRUE;
+
+ /* we're actually adding because step was negated above. This is because
+ * there is no _add function... */
+ if (!gst_value_fraction_subtract (&min, &min, &step)) {
+ GST_WARNING_OBJECT (v4l2camsrc, "could not step fraction!");
+ break;
+ }
+ }
+ if (!added) {
+ /* no range was added, leave the default range from the template */
+ GST_WARNING_OBJECT (v4l2camsrc, "no range added, leaving default");
+ g_value_unset (&rates);
+ }
+ } else if (ival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) {
+ guint32 maxnum, maxdenom;
+
+ g_value_init (&rates, GST_TYPE_FRACTION_RANGE);
+
+ num = ival.stepwise.min.numerator;
+ denom = ival.stepwise.min.denominator;
+ if (num > G_MAXINT || denom > G_MAXINT) {
+ num >>= 1;
+ denom >>= 1;
+ }
+
+ maxnum = ival.stepwise.max.numerator;
+ maxdenom = ival.stepwise.max.denominator;
+ if (maxnum > G_MAXINT || maxdenom > G_MAXINT) {
+ maxnum >>= 1;
+ maxdenom >>= 1;
+ }
+
+ GST_LOG_OBJECT (v4l2camsrc, "continuous frame interval %d/%d to %d/%d",
+ maxdenom, maxnum, denom, num);
+
+ gst_value_set_fraction_range_full (&rates, maxdenom, maxnum, denom, num);
+ } else {
+ goto unknown_type;
+ }
+
+return_data:
+ s = gst_structure_copy (template);
+ /* https://projects.maemo.org/bugzilla/show_bug.cgi?id=105590 */
+ gst_structure_set (s,
+ "width", G_TYPE_INT, (gint) width & ~0x0F,
+ "height", G_TYPE_INT, (gint) height & ~0x0F,
+ NULL);
+
+ if (G_IS_VALUE (&rates)) {
+ /* only change the framerate on the template when we have a valid probed new
+ * value */
+ gst_structure_set_value (s, "framerate", &rates);
+ g_value_unset (&rates);
+ }
+ return s;
+
+ /* ERRORS */
+enum_frameintervals_failed:
+ {
+ GST_DEBUG_OBJECT (v4l2camsrc,
+ "Unable to enumerate intervals for %" GST_FOURCC_FORMAT "@%ux%u",
+ GST_FOURCC_ARGS (pixelformat), width, height);
+ goto return_data;
+ }
+unknown_type:
+ {
+ /* I don't see how this is actually an error, we ignore the format then */
+ GST_WARNING_OBJECT (v4l2camsrc,
+ "Unknown frame interval type at %" GST_FOURCC_FORMAT "@%ux%u: %u",
+ GST_FOURCC_ARGS (pixelformat), width, height, ival.type);
+ return NULL;
+ }
+}
+#endif /* defined VIDIOC_ENUM_FRAMEINTERVALS */
+
+
+/*
+ */
+static gint
+compare_resolutions (gconstpointer a, gconstpointer b)
+{
+ GstStructure *as = (GstStructure *) a;
+ GstStructure *bs = (GstStructure *) b;
+ gint aw, bw, ah, bh;
+
+ gst_structure_get_int (as, "width", &aw);
+ gst_structure_get_int (bs, "width", &bw);
+ gst_structure_get_int (as, "height", &ah);
+ gst_structure_get_int (bs, "height", &bh);
+
+ /* FIXME: What is the best way to compare resolutions if their aspect
+ * ratio isn't the same? */
+ return ((aw-bw) + (ah-bh));
+}
+
+
+/*
+ */
+static gboolean
+fractions_are_equal (gint num1, gint den1, gint num2, gint den2)
+{
+ GValue fraction1 = { 0, }, fraction2 = {
+ 0,};
+
+ g_value_init (&fraction1, GST_TYPE_FRACTION);
+ g_value_init (&fraction2, GST_TYPE_FRACTION);
+ gst_value_set_fraction (&fraction1, num1, den1);
+ gst_value_set_fraction (&fraction2, num2, den2);
+ /* we know we don't have to unset the values in this case */
+ return (gst_value_compare (&fraction1, &fraction2) == GST_VALUE_EQUAL);
+}
+
+
+/*
+ */
+static gboolean
+gst_v4l2camsrc_configure_device (GstV4l2NewCamSrc *v4l2camsrc,
+ guint32 *pixelformat, guint *width, guint *height,
+ guint *fps_n, guint *fps_d)
+{
+ gint fd = v4l2camsrc->video_fd;
+ struct v4l2_format format;
+ struct v4l2_streamparm stream;
+ gboolean ret = TRUE;
+
+ GST_DEBUG_OBJECT (v4l2camsrc, "Configuring device to %dx%d, format "
+ "%" GST_FOURCC_FORMAT, *width, *height, GST_FOURCC_ARGS (*pixelformat));
+
+ GST_V4L2CAMSRC_CHECK_OPEN (v4l2camsrc);
+
+ memset (&format, 0x00, sizeof (struct v4l2_format));
+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if (ioctl (fd, VIDIOC_G_FMT, &format) < 0)
+ goto get_fmt_failed;
+
+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ format.fmt.pix.width = *width;
+ format.fmt.pix.height = *height;
+ format.fmt.pix.pixelformat = *pixelformat;
+ /* request whole frames; change when gstreamer supports interlaced video
+ * (INTERLACED mode returns frames where the fields have already been
+ * combined, there are other modes for requesting fields individually) */
+ format.fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+ if (ioctl (fd, VIDIOC_S_FMT, &format) < 0) {
+ if (errno != EINVAL)
+ goto set_fmt_failed;
+
+ /* try again with progressive video */
+ format.fmt.pix.width = *width;
+ format.fmt.pix.height = *height;
+ format.fmt.pix.pixelformat = *pixelformat;
+ format.fmt.pix.field = V4L2_FIELD_NONE;
+ if (ioctl (fd, VIDIOC_S_FMT, &format) < 0)
+ goto set_fmt_failed;
+ }
+
+ if (format.fmt.pix.width != *width || format.fmt.pix.height != *height)
+ goto invalid_dimensions;
+
+ if (format.fmt.pix.pixelformat != *pixelformat)
+ goto invalid_pixelformat;
+
+ memset (&stream, 0x00, sizeof (struct v4l2_streamparm));
+ stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (ioctl (fd, VIDIOC_G_PARM, &stream) < 0) {
+ GST_ELEMENT_WARNING (v4l2camsrc, RESOURCE, SETTINGS,
+ ("Could not get parameters on device '%s'",
+ v4l2camsrc->videodev), GST_ERROR_SYSTEM);
+ goto done;
+ }
+
+ if (fps_n == NULL || fps_d == NULL) {
+ GST_LOG_OBJECT (v4l2camsrc, "Framerate will not be set");
+ goto done;
+ }
+
+ GST_LOG_OBJECT (v4l2camsrc, "Desired framerate: %u/%u", *fps_n, *fps_d);
+
+ /* Note: V4L2 provides the frame interval, we have the frame rate */
+ if (stream.parm.capture.timeperframe.denominator &&
+ fractions_are_equal (stream.parm.capture.timeperframe.numerator,
+ stream.parm.capture.timeperframe.denominator, *fps_d, *fps_n)) {
+ GST_LOG_OBJECT (v4l2camsrc, "Desired framerate already set, nothing to do");
+ goto done;
+ }
+
+ /* We want to change the frame rate, so check whether we can. Some cheap USB
+ * cameras don't have the capability */
+ if ((stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) == 0) {
+ GST_DEBUG_OBJECT (v4l2camsrc, "Not setting framerate (not supported)");
+ goto done;
+ }
+
+ GST_LOG_OBJECT (v4l2camsrc, "Setting framerate to %u/%u", *fps_n, *fps_d);
+
+ /* Note: V4L2 wants the frame interval, we have the frame rate */
+ stream.parm.capture.timeperframe.numerator = *fps_d;
+ stream.parm.capture.timeperframe.denominator = *fps_n;
+
+ /* some cheap USB cam's won't accept any change */
+ if (ioctl (fd, VIDIOC_S_PARM, &stream) < 0) {
+ GST_ELEMENT_WARNING (v4l2camsrc, RESOURCE, SETTINGS,
+ ("Video input device did not accept new frame rate setting."),
+ GST_ERROR_SYSTEM);
+ goto done;
+ }
+
+ GST_INFO_OBJECT (v4l2camsrc, "Set frame interval to %u/%u",
+ stream.parm.capture.timeperframe.numerator,
+ stream.parm.capture.timeperframe.denominator);
+
+done:
+ v4l2camsrc->max_zoom_factor = 1.0;
+ v4l2camsrc->frame_byte_size = GST_ROUND_UP_2 (*width) * 2 * (*height);
+
+ if (ioctl (v4l2camsrc->video_fd, VIDIOC_CROPCAP, &v4l2camsrc->vcrop) < 0) {
+ GST_DEBUG_OBJECT (v4l2camsrc, "crop not supported");
+ goto no_crop;
+ }
+
+ v4l2camsrc->crop_supported = TRUE;
+
+ GST_DEBUG_OBJECT (v4l2camsrc, "got cropping bounds: x:%d, y:%d, w:%d, h:%d",
+ v4l2camsrc->vcrop.bounds.left,
+ v4l2camsrc->vcrop.bounds.top,
+ v4l2camsrc->vcrop.bounds.width,
+ v4l2camsrc->vcrop.bounds.height);
+
+ GST_DEBUG_OBJECT (v4l2camsrc, "cropping defrect: x:%d, y:%d, w:%d, h:%d",
+ v4l2camsrc->vcrop.defrect.left,
+ v4l2camsrc->vcrop.defrect.top,
+ v4l2camsrc->vcrop.defrect.width,
+ v4l2camsrc->vcrop.defrect.height);
+
+ gst_v4l2camsrc_update_cropping (v4l2camsrc, *width, *height, 1.0);
+
+no_crop:
+
+ return ret;
+
+ /* ERRORS */
+get_fmt_failed:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, SETTINGS,
+ ("Device '%s' does not support video capture",
+ v4l2camsrc->videodev),
+ ("Call to G_FMT failed: (%s)", g_strerror (errno)));
+ return FALSE;
+ }
+set_fmt_failed:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, SETTINGS,
+ ("Device '%s' cannot capture at %dx%d",
+ v4l2camsrc->videodev, *width, *height),
+ ("Call to S_FMT failed for %" GST_FOURCC_FORMAT " @ %dx%d: %s",
+ GST_FOURCC_ARGS (*pixelformat), *width, *height,
+ g_strerror (errno)));
+ return FALSE;
+ }
+invalid_dimensions:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, SETTINGS,
+ ("Device '%s' cannot capture at %dx%d",
+ v4l2camsrc->videodev, *width, *height),
+ ("Tried to capture at %dx%d, but device returned size %dx%d",
+ *width, *height, format.fmt.pix.width, format.fmt.pix.height));
+ return FALSE;
+ }
+invalid_pixelformat:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, SETTINGS,
+ ("Device '%s' cannot capture in the specified format",
+ v4l2camsrc->videodev),
+ ("Tried to capture in %" GST_FOURCC_FORMAT
+ ", but device returned format" " %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (*pixelformat),
+ GST_FOURCC_ARGS (format.fmt.pix.pixelformat)));
+ return FALSE;
+ }
+}
+
+
+/**
+ * gst_v4l2camsrc_probe_caps_for_format:
+ * @v4l2camsrc: #GstV4l2NewCamSrc object
+ * @pixelformat: pixel format fourcc
+ * @template: GstStructure template to be used for generating the caps
+ *
+ * Creates GstCaps object which describes the supported caps of the device.
+ *
+ * Returns: GStCaps containing supported video resolutions.
+ */
+GstCaps *
+gst_v4l2camsrc_probe_caps_for_format (GstV4l2NewCamSrc * v4l2camsrc,
+ guint32 pixelformat, const GstStructure * template)
+{
+ GstCaps *ret = gst_caps_new_empty ();
+ gint min_w, max_w, min_h, max_h;
+ GstStructure *tmp;
+
+ min_w = min_h = 1;
+ max_w = max_h = GST_CAMERA_SRC_MAX_SIZE;
+ if (!gst_v4l2camsrc_get_nearest_size (v4l2camsrc, pixelformat,
+ &min_w, &min_h))
+ {
+ GST_WARNING_OBJECT (v4l2camsrc,
+ "Could not probe minimum capture size for pixelformat %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat));
+ }
+ if (!gst_v4l2camsrc_get_nearest_size (v4l2camsrc, pixelformat,
+ &max_w, &max_h))
+ {
+ GST_WARNING_OBJECT (v4l2camsrc,
+ "Could not probe maximum capture size for pixelformat %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat));
+ }
+
+#ifdef VIDIOC_ENUM_FRAMESIZES
+ {
+ gint fd = v4l2camsrc->video_fd;
+ struct v4l2_frmsizeenum size;
+ GList *results = NULL;
+ gint w, h;
+
+ memset (&size, 0, sizeof (struct v4l2_frmsizeenum));
+ size.index = 0;
+ size.pixel_format = pixelformat;
+
+ if (ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0)
+ goto enum_framesizes_failed;
+
+ if (size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
+ do {
+ w = MIN (size.discrete.width, G_MAXINT);
+ h = MIN (size.discrete.height, G_MAXINT);
+
+ tmp = gst_v4l2camsrc_probe_caps_for_format_and_size (v4l2camsrc,
+ pixelformat, w, h, template);
+
+ if (tmp)
+ results = g_list_prepend (results, tmp);
+
+ size.index++;
+ } while (ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0);
+ } else {
+ goto unknown_type;
+ }
+
+ /* Sort the resolutions from smallest to largest */
+ results = g_list_sort (results, compare_resolutions);
+
+ /* If we have resizer we can use ranges instead of discrete
+ resolutions reported by driver. FIXME: how to detect resizer?
+ It would be nice if the resizer was transparent to v4l2camsrc.
+ */
+ while (results != NULL) {
+ tmp = GST_STRUCTURE (results->data);
+ gst_structure_get_int (tmp, "width", &max_w);
+ gst_structure_get_int (tmp, "height", &max_h);
+
+ min_w = max_w / RESIZER_MAX_DOWNSCALE_FACTOR;
+ min_h = max_h / RESIZER_MAX_DOWNSCALE_FACTOR;
+
+ GST_DEBUG_OBJECT (v4l2camsrc,
+ "Setting up range %dx%d - %dx%d", min_w, min_h, max_w, max_h);
+
+ gst_structure_set (tmp,
+ "width", GST_TYPE_INT_RANGE, min_w, max_w,
+ "height", GST_TYPE_INT_RANGE, min_h,max_h,
+ NULL);
+
+ gst_caps_append_structure (ret, tmp);
+
+ results = g_list_delete_link (results, results);
+ }
+
+ if (gst_caps_is_empty (ret))
+ goto enum_framesizes_no_results;
+
+ return ret;
+
+ /* ERRORS */
+ enum_framesizes_failed:
+ {
+ /* I don't see how this is actually an error */
+ GST_DEBUG_OBJECT (v4l2camsrc,
+ "Failed to enumerate frame sizes for pixelformat %" GST_FOURCC_FORMAT
+ " (%s)", GST_FOURCC_ARGS (pixelformat), g_strerror (errno));
+ goto default_frame_sizes;
+ }
+ enum_framesizes_no_results:
+ {
+ /* it's possible that VIDIOC_ENUM_FRAMESIZES is defined but the driver in
+ * question doesn't actually support it yet */
+ GST_DEBUG_OBJECT (v4l2camsrc, "No results for pixelformat %"
+ GST_FOURCC_FORMAT " enumerating frame sizes, trying fallback",
+ GST_FOURCC_ARGS (pixelformat));
+ goto default_frame_sizes;
+ }
+ unknown_type:
+ {
+ GST_WARNING_OBJECT (v4l2camsrc,
+ "Unknown frame sizeenum type for pixelformat %" GST_FOURCC_FORMAT
+ ": %u", GST_FOURCC_ARGS (pixelformat), size.type);
+ goto default_frame_sizes;
+ }
+ }
+#endif /* defined VIDIOC_ENUM_FRAMESIZES */
+
+default_frame_sizes:
+
+ tmp = gst_structure_copy (template);
+ gst_structure_set (tmp,
+ "width", GST_TYPE_INT_RANGE, min_w, max_w,
+ "height", GST_TYPE_INT_RANGE, min_h, max_h, NULL);
+ gst_caps_append_structure (ret, tmp);
+
+ return ret;
+}
+
+/******************************************************
+ * gst_v4l2camsrc_grab_frame ():
+ * grab a frame for capturing
+ * return value: GST_FLOW_OK, GST_FLOW_WRONG_STATE or GST_FLOW_ERROR
+ ******************************************************/
+GstFlowReturn
+gst_v4l2camsrc_grab_frame (GstCameraSrc *camsrc, GstBuffer ** buf,
+ GstCameraCapturePhase phase)
+{
+ GstV4l2NewCamSrc *v4l2camsrc = GST_V4L2CAMSRC (camsrc);
+
+#define NUM_TRIALS 50
+ struct v4l2_buffer buffer;
+ gint32 trials = NUM_TRIALS;
+ GstBuffer *pool_buffer;
+ gboolean need_copy = TRUE; /* FIXME Need copy for the buffer */
+ gint index;
+ gint ret;
+
+ /* wait if all buffers are DQBuf */
+#if 0
+ g_mutex_lock (v4l2camsrc->device_mutex);
+ gst_v4l2_buffer_pool_update (v4l2camsrc->pool, v4l2camsrc);
+ g_mutex_unlock (v4l2camsrc->device_mutex);
+#endif
+
+ memset (&buffer, 0x00, sizeof (buffer));
+ buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buffer.memory = V4L2_MEMORY_USERPTR;
+
+ if (phase == GST_CAMERA_CAPTURE) {
+ gst_camerasrc_send_capture_start_message (camsrc);
+ }
+
+ for (;;) {
+ ret = gst_poll_wait (v4l2camsrc->poll, V4L2CAMSRC_POLL_TIMEOUT);
+ if (G_UNLIKELY (ret < 0)) {
+ if (errno == EBUSY)
+ goto stopped;
+ if (errno != EAGAIN && errno != EINTR)
+ goto select_error;
+ }
+
+ if (G_UNLIKELY (ret == 0)) {
+ goto timeout;
+ }
+ g_mutex_lock (v4l2camsrc->device_mutex);
+ ret = ioctl (v4l2camsrc->video_fd, VIDIOC_DQBUF, &buffer);
+ g_mutex_unlock (v4l2camsrc->device_mutex);
+
+ if (ret >= 0)
+ break;
+
+ GST_WARNING_OBJECT (v4l2camsrc,
+ "problem grabbing frame %d (ix=%d), trials=%d, pool-ct=%d, buf.flags=%d",
+ buffer.sequence, buffer.index, trials,
+ GST_MINI_OBJECT_REFCOUNT (v4l2camsrc->pool), buffer.flags);
+
+ /* if the sync() got interrupted, we can retry */
+ switch (errno) {
+ case EAGAIN:
+ GST_WARNING_OBJECT (v4l2camsrc,
+ "Non-blocking I/O has been selected using O_NONBLOCK and"
+ " no buffer was in the outgoing queue. device %s",
+ v4l2camsrc->videodev);
+ break;
+ case EINVAL:
+ goto einval;
+ case ENOMEM:
+ goto enomem;
+ case EIO:
+ GST_INFO_OBJECT (v4l2camsrc,
+ "VIDIOC_DQBUF failed due to an internal error."
+ " Can also indicate temporary problems like signal loss."
+ " Note the driver might dequeue an (empty) buffer despite"
+ " returning an error, or even stop capturing."
+ " device %s", v4l2camsrc->videodev);
+ /* have we de-queued a buffer ? */
+ if (!(buffer.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))) {
+ /* this fails
+ if ((buffer.index >= 0) && (buffer.index < v4l2camsrc->breq.count)) {
+ GST_DEBUG_OBJECT (v4l2camsrc, "reenqueing buffer (ix=%ld)", buffer.index);
+ gst_v4l2camsrc_queue_frame (v4l2camsrc, buffer.index);
+ }
+ else {
+ */
+ GST_DEBUG_OBJECT (v4l2camsrc, "reenqueing buffer");
+ /* FIXME: this is not a good idea, as drivers usualy return the buffer
+ * with index-number set to 0, thus the re-enque will fail unless it
+ * was incidentialy 0.
+ * We could try to re-enque all buffers without handling the ioctl
+ * return.
+ */
+ /*
+ if (ioctl (v4l2camsrc->video_fd, VIDIOC_QBUF, &buffer) < 0) {
+ goto qbuf_failed;
+ }
+ */
+ /*} */
+ }
+ break;
+ case EINTR:
+ GST_WARNING_OBJECT (v4l2camsrc,
+ "could not sync on a buffer on device %s",
+ v4l2camsrc->videodev);
+ break;
+ default:
+ GST_WARNING_OBJECT (v4l2camsrc,
+ "Grabbing frame got interrupted on %s. No expected reason.",
+ v4l2camsrc->videodev);
+ break;
+ }
+
+ /* check nr. of attempts to capture */
+ if (--trials == -1) {
+ goto too_many_trials;
+ } else {
+ memset (&buffer, 0x00, sizeof (buffer));
+ buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buffer.memory = V4L2_MEMORY_USERPTR;
+ }
+ }
+
+ if (phase == GST_CAMERA_CAPTURE) {
+ gst_camerasrc_send_capture_stop_message (camsrc);
+ }
+
+ g_mutex_lock (v4l2camsrc->pool->lock);
+
+ index = buffer.index;
+
+ /* get our GstBuffer with that index from the pool, if the buffer is
+ * in use (NULL) we have a serious problem (should only be possible in mmap
+ * case). */
+ pool_buffer = GST_BUFFER (v4l2camsrc->pool->buffers[index]);
+
+ if (G_UNLIKELY (pool_buffer == NULL))
+ goto no_buffer;
+
+ GST_LOG_OBJECT (v4l2camsrc, "grabbed buffer %p at index %d (refct = %d)",
+ pool_buffer, index, GST_MINI_OBJECT_REFCOUNT (pool_buffer));
+
+ /* ref the buffer and requeue, when if becomes writable again */
+ v4l2camsrc->pool->buffers[index] = NULL;
+ v4l2camsrc->pool->num_live_buffers++;
+ v4l2camsrc->pool->queued[index] = 0;
+
+ g_mutex_unlock (v4l2camsrc->pool->lock);
+
+ /* this can change at every frame, esp. with jpeg */
+ GST_BUFFER_SIZE (pool_buffer) = buffer.bytesused;
+
+ GST_BUFFER_OFFSET (pool_buffer) = v4l2camsrc->offset++;
+ GST_BUFFER_OFFSET_END (pool_buffer) = v4l2camsrc->offset;
+
+ /* timestamps, LOCK to get clock and base time. */
+ {
+ GstClock *clock;
+ GstClockTime timestamp;
+
+ GST_OBJECT_LOCK (v4l2camsrc);
+ if ((clock = GST_ELEMENT_CLOCK (v4l2camsrc))) {
+ /* we have a clock, get base time and ref clock */
+ timestamp = GST_ELEMENT (v4l2camsrc)->base_time;
+ gst_object_ref (clock);
+ } else {
+ /* no clock, can't set timestamps */
+ timestamp = GST_CLOCK_TIME_NONE;
+ }
+ GST_OBJECT_UNLOCK (v4l2camsrc);
+
+ if (clock) {
+ GstClockTime latency;
+
+ /* the time now is the time of the clock minus the base time */
+ timestamp = gst_clock_get_time (clock) - timestamp;
+ gst_object_unref (clock);
+
+ latency =
+ gst_util_uint64_scale_int (GST_SECOND, camsrc->fps_d,
+ camsrc->fps_n);
+
+ if (timestamp > latency)
+ timestamp -= latency;
+ else
+ timestamp = 0;
+ GST_BUFFER_DURATION (pool_buffer) = latency;
+ }
+
+ /* FIXME: use the timestamp from the buffer itself! */
+ GST_BUFFER_TIMESTAMP (pool_buffer) = timestamp;
+ }
+
+ if (G_UNLIKELY (need_copy)) {
+ GST_DEBUG_OBJECT (v4l2camsrc, "copying buffer");
+ *buf = gst_buffer_copy (pool_buffer);
+ GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY);
+ /* this will requeue */
+ gst_buffer_unref (pool_buffer);
+ } else {
+ *buf = pool_buffer;
+ }
+
+ GST_LOG_OBJECT (v4l2camsrc, "grabbed frame %d (ix=%d), flags %08x, pool-ct=%d",
+ buffer.sequence, buffer.index, buffer.flags,
+ v4l2camsrc->pool->num_live_buffers);
+
+ return GST_FLOW_OK;
+
+ /* ERRORS */
+select_error:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, READ, (NULL),
+ ("select error %d: %s (%d)", ret, g_strerror (errno), errno));
+ return GST_FLOW_ERROR;
+ }
+stopped:
+ {
+ GST_DEBUG ("stop called");
+ return GST_FLOW_WRONG_STATE;
+ }
+einval:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, FAILED,
+ ("Failed trying to get video frames from device '%s'.",
+ v4l2camsrc->videodev),
+ ("The buffer type is not supported, or the index is out of bounds,"
+ " or no buffers have been allocated yet, or the userptr"
+ " or length are invalid. device %s",
+ v4l2camsrc->videodev));
+ return GST_FLOW_ERROR;
+ }
+enomem:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, FAILED,
+ ("Failed trying to get video frames from device '%s'. Not enough memory.",
+ v4l2camsrc->videodev), ("insufficient memory to enqueue a user "
+ "pointer buffer. device %s.", v4l2camsrc->videodev));
+ return GST_FLOW_ERROR;
+ }
+too_many_trials:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, FAILED,
+ ("Failed trying to get video frames from device '%s'.",
+ v4l2camsrc->videodev),
+ ("Failed after %d tries. device %s. system error: %s",
+ NUM_TRIALS, v4l2camsrc->videodev, g_strerror (errno)));
+ return GST_FLOW_ERROR;
+ }
+no_buffer:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, FAILED,
+ ("Failed trying to get video frames from device '%s'.",
+ v4l2camsrc->videodev),
+ ("No free buffers found in the pool at index %d.", index));
+ g_mutex_unlock (v4l2camsrc->pool->lock);
+ return GST_FLOW_ERROR; }
+/*
+qbuf_failed:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, WRITE,
+ ("Could not exchange data with device '%s'.",
+ v4l2camsrc->videodev),
+ ("Error queueing buffer on device %s. system error: %s",
+ v4l2camsrc->videodev, g_strerror (errno)));
+ return GST_FLOW_ERROR;
+ }
+*/
+timeout:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, FAILED,
+ ("Timeout when trying to get video frames from device '%s'.",
+ v4l2camsrc->videodev), NULL);
+ return GST_FLOW_ERROR;
+ }
+}
+
+
+/******************************************************
+ * gst_v4l2camsrc_set_capture():
+ * set capture parameters for certain operation mode
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+gboolean
+gst_v4l2camsrc_set_capture (GstCameraSrc *camsrc, GstOperationMode mode,
+ gboolean try_only, guint32 *pixelformat, guint *width, guint *height,
+ guint *fps_n, guint *fps_d)
+{
+ GstV4l2NewCamSrc *v4l2camsrc = GST_V4L2CAMSRC (camsrc);
+ gboolean ret = TRUE;
+
+ if (mode == GST_PHOTOGRAPHY_OPERATION_MODE_PREVIEW) {
+ return FALSE;
+ }
+ else if (mode == GST_PHOTOGRAPHY_OPERATION_MODE_IMAGE_CAPTURE) {
+ GST_DEBUG_OBJECT (v4l2camsrc, "Image capture: %dx%d, format "
+ "%" GST_FOURCC_FORMAT, *width, *height, GST_FOURCC_ARGS (*pixelformat));
+
+ if (try_only) {
+ /* Round width & height down to be dividable by 8 */
+ *width = (*width) & ~7;
+ *height = (*height) & ~7;
+ ret = TRUE;
+ }
+ else {
+ ret = gst_v4l2camsrc_configure_device (v4l2camsrc, pixelformat,
+ width, height, fps_n, fps_d);
+ v4l2camsrc->tmp_num_buffers = v4l2camsrc->num_buffers;
+ v4l2camsrc->num_buffers = 1;
+
+ v4l2camsrc->capture_w = *width;
+ v4l2camsrc->capture_h = *height;
+ v4l2camsrc->capture_fps_n = *fps_n;
+ v4l2camsrc->capture_fps_d = *fps_d;
+ v4l2camsrc->capture_fourcc = *pixelformat;
+ }
+ }
+ else {
+ v4l2camsrc->num_buffers = v4l2camsrc->tmp_num_buffers;
+
+ ret = gst_v4l2camsrc_configure_device (v4l2camsrc, pixelformat,
+ width, height, fps_n, fps_d);
+
+ v4l2camsrc->vf_w = *width;
+ v4l2camsrc->vf_h = *height;
+ v4l2camsrc->vf_fourcc = *pixelformat;
+ v4l2camsrc->vf_fps_n = *fps_n;
+ v4l2camsrc->vf_fps_d = *fps_d;
+ }
+
+ return ret;
+}
+
+/******************************************************
+ * gst_v4l2camsrc_capture_start():
+ * Start capturing frames from the device
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+gboolean
+gst_v4l2camsrc_capture_start (GstCameraSrc *camsrc, GstCaps * caps)
+{
+ GstV4l2NewCamSrc *v4l2camsrc = GST_V4L2CAMSRC (camsrc);
+
+ gint fd = v4l2camsrc->video_fd;
+ struct v4l2_requestbuffers breq;
+ gint type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ v4l2camsrc->offset = 0;
+
+ memset (&breq, 0, sizeof (struct v4l2_requestbuffers));
+
+ GST_DEBUG_OBJECT (v4l2camsrc, "initializing the capture system");
+
+ GST_V4L2CAMSRC_CHECK_OPEN (v4l2camsrc);
+ GST_V4L2CAMSRC_CHECK_NOT_ACTIVE (v4l2camsrc);
+
+ if (!(v4l2camsrc->vcap.capabilities & V4L2_CAP_STREAMING))
+ goto no_capture_method;
+
+ GST_DEBUG_OBJECT (v4l2camsrc, "STREAMING, requesting %d CAPTURE buffers",
+ v4l2camsrc->num_buffers);
+
+ breq.count = v4l2camsrc->num_buffers;
+ breq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ breq.memory = V4L2_MEMORY_USERPTR;
+
+ if (ioctl (fd, VIDIOC_REQBUFS, &breq) < 0)
+ goto reqbufs_failed;
+
+ GST_LOG_OBJECT (v4l2camsrc, " count: %u", breq.count);
+ GST_LOG_OBJECT (v4l2camsrc, " type: %d", breq.type);
+ GST_LOG_OBJECT (v4l2camsrc, " memory: %d", breq.memory);
+
+ if (breq.count < GST_V4L2CAMSRC_MIN_BUFFERS)
+ goto no_buffers;
+
+ if (v4l2camsrc->num_buffers != breq.count) {
+ GST_WARNING_OBJECT (v4l2camsrc, "using %u buffers instead", breq.count);
+ v4l2camsrc->num_buffers = breq.count;
+ g_object_notify (G_OBJECT (v4l2camsrc), "queue-size");
+ }
+
+ /* Map the buffers */
+ GST_LOG_OBJECT (v4l2camsrc, "initiating buffer pool");
+
+ if (!(v4l2camsrc->pool = gst_v4l2camsrc_buffer_pool_new (v4l2camsrc, fd, caps)))
+ goto buffer_pool_new_failed;
+
+ GST_INFO_OBJECT (v4l2camsrc, "capturing buffers");
+
+ GST_V4L2CAMSRC_SET_ACTIVE (v4l2camsrc);
+
+ GST_DEBUG_OBJECT (v4l2camsrc, "starting the capturing");
+ GST_V4L2CAMSRC_CHECK_ACTIVE (v4l2camsrc);
+
+ if (!gst_v4l2camsrc_buffer_pool_activate (v4l2camsrc->pool, v4l2camsrc))
+ goto pool_activate_failed;
+
+ if (ioctl (fd, VIDIOC_STREAMON, &type) < 0)
+ goto streamon_failed;
+
+ GST_DEBUG_OBJECT (v4l2camsrc, "STREAMON called");
+
+ return TRUE;
+
+ /* ERRORS */
+reqbufs_failed:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, READ,
+ ("Could not get buffers from device '%s'.",
+ v4l2camsrc->videodev),
+ ("error requesting %d buffers: %s",
+ v4l2camsrc->num_buffers, g_strerror (errno)));
+ return FALSE;
+ }
+no_buffers:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, READ,
+ ("Could not get enough buffers from device '%s'.",
+ v4l2camsrc->videodev),
+ ("we received %d from device '%s', we want at least %d",
+ breq.count, v4l2camsrc->videodev, GST_V4L2CAMSRC_MIN_BUFFERS));
+ return FALSE;
+ }
+buffer_pool_new_failed:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, READ,
+ ("Could not map buffers from device '%s'",
+ v4l2camsrc->videodev),
+ ("Failed to create buffer pool: %s", g_strerror (errno)));
+ return FALSE;
+ }
+no_capture_method:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, READ,
+ ("The driver of device '%s' does not support streaming. ",
+ v4l2camsrc->videodev), (NULL));
+ return FALSE;
+ }
+pool_activate_failed:
+ {
+ /* already errored */
+ return FALSE;
+ }
+streamon_failed:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, OPEN_READ,
+ ("Error starting streaming capture from device '%s'.",
+ v4l2camsrc->videodev), GST_ERROR_SYSTEM);
+ return FALSE;
+ }
+}
+
+/******************************************************
+ * gst_v4l2camsrc_capture_stop():
+ * stop streaming capture
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+gboolean
+gst_v4l2camsrc_capture_stop (GstCameraSrc *camsrc)
+{
+ GstV4l2NewCamSrc *v4l2camsrc = GST_V4L2CAMSRC (camsrc);
+
+ gint type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ GST_DEBUG_OBJECT (v4l2camsrc, "stopping capturing");
+
+ if (!GST_V4L2CAMSRC_IS_OPEN (v4l2camsrc)) {
+ return TRUE;
+ }
+ if (!GST_V4L2CAMSRC_IS_ACTIVE (v4l2camsrc)) {
+ return TRUE;
+ }
+
+ /* we actually need to sync on all queued buffers but not
+ * on the non-queued ones */
+ if (ioctl (v4l2camsrc->video_fd, VIDIOC_STREAMOFF, &type) < 0)
+ goto streamoff_failed;
+
+ GST_DEBUG_OBJECT (v4l2camsrc, "STREAMOFF called");
+
+ if (v4l2camsrc->pool) {
+ gst_v4l2camsrc_buffer_pool_destroy (v4l2camsrc->pool, v4l2camsrc);
+ v4l2camsrc->pool = NULL;
+ }
+
+ GST_V4L2CAMSRC_SET_INACTIVE (v4l2camsrc);
+
+ return TRUE;
+
+ /* ERRORS */
+streamoff_failed:
+ {
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, CLOSE,
+ ("Error stopping streaming capture from device '%s'.",
+ v4l2camsrc->videodev), GST_ERROR_SYSTEM);
+ return FALSE;
+ }
+}
+
+/*
+ */
+static gboolean
+gst_v4l2camsrc_get_nearest_size (GstV4l2NewCamSrc * v4l2camsrc, guint32 pixelformat,
+ gint * width, gint * height)
+{
+ struct v4l2_format fmt;
+ int fd;
+ int r;
+
+ g_return_val_if_fail (width != NULL, FALSE);
+ g_return_val_if_fail (height != NULL, FALSE);
+
+ GST_LOG_OBJECT (v4l2camsrc,
+ "getting nearest size to %dx%d with format %" GST_FOURCC_FORMAT,
+ *width, *height, GST_FOURCC_ARGS (pixelformat));
+
+ fd = v4l2camsrc->video_fd;
+
+ /* get size delimiters */
+ memset (&fmt, 0, sizeof (fmt));
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmt.fmt.pix.width = *width;
+ fmt.fmt.pix.height = *height;
+ fmt.fmt.pix.pixelformat = pixelformat;
+ fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+ r = ioctl (fd, VIDIOC_TRY_FMT, &fmt);
+ if (r < 0 && errno == EINVAL) {
+ /* try again with progressive video */
+ fmt.fmt.pix.width = *width;
+ fmt.fmt.pix.height = *height;
+ fmt.fmt.pix.pixelformat = pixelformat;
+ fmt.fmt.pix.field = V4L2_FIELD_NONE;
+ r = ioctl (fd, VIDIOC_TRY_FMT, &fmt);
+ }
+
+ if (r < 0) {
+ /* The driver might not implement TRY_FMT, in which case we will try
+ S_FMT to probe */
+ if (errno != ENOTTY)
+ return FALSE;
+
+ /* Only try S_FMT if we're not actively capturing yet, which we shouldn't
+ be, because we're still probing */
+ if (GST_V4L2CAMSRC_IS_ACTIVE (v4l2camsrc))
+ return FALSE;
+
+ GST_LOG_OBJECT (v4l2camsrc,
+ "Failed to probe size limit with VIDIOC_TRY_FMT, trying VIDIOC_S_FMT");
+
+ fmt.fmt.pix.width = *width;
+ fmt.fmt.pix.height = *height;
+
+ r = ioctl (fd, VIDIOC_S_FMT, &fmt);
+ if (r < 0 && errno == EINVAL) {
+ /* try again with progressive video */
+ fmt.fmt.pix.width = *width;
+ fmt.fmt.pix.height = *height;
+ fmt.fmt.pix.pixelformat = pixelformat;
+ fmt.fmt.pix.field = V4L2_FIELD_NONE;
+ r = ioctl (fd, VIDIOC_S_FMT, &fmt);
+ }
+
+ if (r < 0)
+ return FALSE;
+ }
+
+ GST_LOG_OBJECT (v4l2camsrc,
+ "got nearest size %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height);
+
+ *width = fmt.fmt.pix.width;
+ *height = fmt.fmt.pix.height;
+
+ return TRUE;
+}
+
+
+/******************************************************
+ * gst_v4l2camsrc_set_crop():
+ * set cropping bounds
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+static gboolean
+gst_v4l2camsrc_set_crop (GstV4l2NewCamSrc *v4l2camsrc,
+ gint x, gint y, gint w, gint h)
+{
+ gboolean ret = FALSE;
+ struct v4l2_crop scrop;
+ struct v4l2_crop gcrop;
+ gint cx, cy, cw, ch;
+ int fd;
+
+ fd = v4l2camsrc->video_fd;
+ cx = v4l2camsrc->vcrop.bounds.left;
+ cy = v4l2camsrc->vcrop.bounds.top;
+ cw = v4l2camsrc->vcrop.bounds.width;
+ ch = v4l2camsrc->vcrop.bounds.height;
+
+ memset (&scrop, 0, sizeof (scrop));
+ scrop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ /* Make sure that cropping area stays inside the crop boundaries */
+ scrop.c.left = x > cx ? x : cx;
+ scrop.c.top = y > cy ? y : cy;
+ scrop.c.width = (scrop.c.left+w) < (cx+cw) ? w : cx+cw-scrop.c.left;
+ scrop.c.height = (scrop.c.top+h) < (cy+ch) ? h : cy+ch-scrop.c.top;
+
+ GST_DEBUG_OBJECT (v4l2camsrc,
+ "Crop request: left = %d, top = %d, w = %d, h = %d",
+ scrop.c.left, scrop.c.top, scrop.c.width, scrop.c.height);
+
+ g_mutex_lock (v4l2camsrc->device_mutex);
+
+ if (-1 == ioctl (fd, VIDIOC_S_CROP, &scrop) && errno != EINVAL) {
+ goto s_crop_failed;
+ }
+
+ if (-1 == ioctl (fd, VIDIOC_G_CROP, &gcrop)) {
+ goto g_crop_failed;
+ }
+
+ g_mutex_unlock (v4l2camsrc->device_mutex);
+
+ GST_DEBUG_OBJECT (v4l2camsrc,
+ "Crop selected: left = %d, top = %d, w = %d, h = %d",
+ gcrop.c.left, gcrop.c.top, gcrop.c.width, gcrop.c.height);
+
+#if 0
+ if (gcrop.c.left != scrop.c.left || gcrop.c.top != scrop.c.top ||
+ gcrop.c.width != scrop.c.width || gcrop.c.height != scrop.c.height)
+ {
+ goto crop_not_supported;
+ }
+#endif
+
+ ret = TRUE;
+
+done:
+
+ return ret;
+
+/* ERRORS */
+s_crop_failed:
+ g_mutex_unlock (v4l2camsrc->device_mutex);
+ GST_DEBUG_OBJECT (v4l2camsrc, "VIDIOC_S_CROP not supported");
+ goto done;
+
+g_crop_failed:
+ g_mutex_unlock (v4l2camsrc->device_mutex);
+ GST_DEBUG_OBJECT (v4l2camsrc, "VIDIOC_G_CROP not supported");
+ goto done;
+
+#if 0
+crop_not_supported:
+ g_mutex_unlock (v4l2camsrc->device_mutex);
+ GST_DEBUG_OBJECT (v4l2camsrc, "Given crop value not accepted");
+ goto done;
+#endif
+}
+
+
+/******************************************************
+ * gst_v4l2camsrc_update_cropping():
+ * update cropping area according to width, height and zoom factors.
+ * return value: TRUE on success, FALSE on error
+ ******************************************************/
+static gboolean
+gst_v4l2camsrc_update_cropping (GstV4l2NewCamSrc *v4l2camsrc, gint width,
+ gint height, gfloat zoom)
+{
+ gfloat sensor_ar, reso_ar;
+ gint crop_x, crop_y, crop_w, crop_h;
+
+ g_return_val_if_fail (width != 0, FALSE);
+ g_return_val_if_fail (height != 0, FALSE);
+ g_return_val_if_fail (zoom != 0, FALSE);
+
+ if (zoom < 1.0 || zoom > v4l2camsrc->max_zoom_factor) {
+ GST_DEBUG_OBJECT (v4l2camsrc, "invalid zoom = %.2f", zoom);
+ return FALSE;
+ }
+ if (!v4l2camsrc->crop_supported) {
+ GST_DEBUG_OBJECT (v4l2camsrc, "crop not supported");
+ return FALSE;
+ }
+
+ sensor_ar = v4l2camsrc->vcrop.defrect.width /
+ v4l2camsrc->vcrop.defrect.height;
+ reso_ar = width / height;
+
+ if (sensor_ar > reso_ar) {
+ crop_w = (width * v4l2camsrc->vcrop.defrect.height / height) / zoom;
+ crop_h = MAX (v4l2camsrc->vcrop.defrect.height, height) / zoom;
+ }
+ else {
+ crop_w = MAX (v4l2camsrc->vcrop.defrect.width, width) / zoom;
+ crop_h = (height * v4l2camsrc->vcrop.defrect.width / width) / zoom;
+ }
+
+ crop_x = ABS ((v4l2camsrc->vcrop.defrect.width - crop_w) / 2);
+ crop_y = ABS ((v4l2camsrc->vcrop.defrect.height - crop_h) / 2);
+
+ GST_LOG_OBJECT (v4l2camsrc, "set cropping: x: %d, y: %d, w: %d, h: %d",
+ crop_x, crop_y, crop_w, crop_h);
+
+ return gst_v4l2camsrc_set_crop (v4l2camsrc, crop_x, crop_y, crop_w, crop_h);
+}
--- /dev/null
+/* GStreamer
+ *
+ * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ * 2006 Edgard Lima <edgard.lima@indt.org.br>
+ * 2008-2010 Nokia Corporation <multimedia@maemo.org>
+ *
+ * v4l2camsrc.h - system calls
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should 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 __V4L2CAMSRC_CALLS_H__
+#define __V4L2CAMSRC_CALLS_H__
+
+#include "gstv4l2camsrc.h"
+
+/* simple check whether the device is open */
+#define GST_V4L2CAMSRC_IS_OPEN(v4l2camsrc) \
+ (v4l2camsrc->video_fd > 0)
+
+/* check whether the device is 'active' */
+#define GST_V4L2CAMSRC_IS_ACTIVE(v4l2camsrc) \
+ (v4l2camsrc->buffer != NULL)
+
+#define GST_V4L2CAMSRC_IS_OVERLAY(v4l2camsrc) \
+ (v4l2camsrc->vcap.capabilities & V4L2CAMSRC_CAP_VIDEO_OVERLAY)
+
+/* checks whether the current v4lv4l2object has already been open()'ed or not */
+#define GST_V4L2CAMSRC_CHECK_OPEN(v4l2camsrc) \
+ if (!GST_V4L2CAMSRC_IS_OPEN(v4l2camsrc)) \
+{ \
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, SETTINGS, \
+ ("Device is not open."), (NULL)); \
+ return FALSE; \
+}
+
+/* checks whether the current v4lv4l2object is close()'ed or whether it is still open */
+#define GST_V4L2CAMSRC_CHECK_NOT_OPEN(v4l2camsrc) \
+ if (GST_V4L2CAMSRC_IS_OPEN(v4l2camsrc)) \
+{ \
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, SETTINGS, \
+ ("Device is open."), (NULL)); \
+ return FALSE; \
+}
+
+/* checks whether we're in capture mode or not */
+#define GST_V4L2CAMSRC_CHECK_ACTIVE(v4l2camsrc) \
+ if (!GST_V4L2CAMSRC_IS_ACTIVE(v4l2camsrc)) \
+{ \
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, SETTINGS, \
+ (NULL), ("Device is not in streaming mode")); \
+ return FALSE; \
+}
+
+/* checks whether we're out of capture mode or not */
+#define GST_V4L2CAMSRC_CHECK_NOT_ACTIVE(v4l2camsrc) \
+ if (GST_V4L2CAMSRC_IS_ACTIVE(v4l2camsrc)) \
+{ \
+ GST_ELEMENT_ERROR (v4l2camsrc, RESOURCE, SETTINGS, \
+ (NULL), ("Device is in streaming mode")); \
+ return FALSE; \
+}
+
+
+#define GST_V4L2CAMSRC_MAX_BUFFERS 16
+#define GST_V4L2CAMSRC_MIN_BUFFERS 1
+#define GST_V4L2CAMSRC_DEFAULT_BUFFERS 4
+
+
+/* open/close the device */
+gboolean gst_v4l2camsrc_open (GstCameraSrc *camsrc);
+
+gboolean gst_v4l2camsrc_close (GstCameraSrc *camsrc);
+
+/* attribute control */
+gboolean gst_v4l2camsrc_get_attribute (GstCameraSrc *camsrc,
+ int attribute,
+ int *value);
+
+gboolean gst_v4l2camsrc_set_attribute (GstCameraSrc *camsrc,
+ int attribute,
+ const int value);
+
+gboolean gst_v4l2camsrc_set_capture (GstCameraSrc *camsrc,
+ GstOperationMode mode,
+ gboolean try_only,
+ guint32 *pixelformat,
+ guint *width, guint *height,
+ guint *fps_n, guint *fps_d);
+
+gboolean gst_v4l2camsrc_capture_start (GstCameraSrc *camsrc,
+ GstCaps *caps);
+
+GstFlowReturn gst_v4l2camsrc_grab_frame (GstCameraSrc *camsrc,
+ GstBuffer **buf,
+ GstCameraCapturePhase phase);
+
+gboolean gst_v4l2camsrc_capture_stop (GstCameraSrc *camsrc);
+
+/* Used internally */
+gboolean gst_v4l2camsrc_fill_format_list (GstV4l2NewCamSrc *v4l2camsrc);
+gboolean gst_v4l2camsrc_clear_format_list (GstV4l2NewCamSrc *v4l2camsrc);
+GstCaps * gst_v4l2camsrc_probe_caps_for_format (GstV4l2NewCamSrc *v4l2camsrc,
+ guint32 pixelformat,
+ const GstStructure *template);
+
+
+#endif /* __V4L2CAMSRC_CALLS_H__ */
--- /dev/null
+### all of the standard pc files we need to generate
+pcverfiles = \
+ gstreamer-nokia-videosrc-@GST_MAJORMINOR@.pc
+
+all-local: $(pcverfiles)
+
+### how to generate versioned .pc files from .pc files in this dir
+%-@GST_MAJORMINOR@.pc: %.pc
+ cp $< $@
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = $(pcverfiles)
+
+CLEANFILES = $(pcverfiles)
+pcinfiles = \
+ gstreamer-nokia-videosrc.pc.in
+
+DISTCLEANFILES = $(pcinfiles:.in=)
+EXTRA_DIST = $(pcinfiles)
--- /dev/null
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@/gstreamer-@GST_MAJORMINOR@
+
+Name: GStreamer Camera Plugin libraries
+Description: GStreamer Camera base class API
+Requires: gstreamer-@GST_MAJORMINOR@
+Version: @VERSION@
+Libs: -L${libdir}
+Cflags: -I${includedir}